-
Notifications
You must be signed in to change notification settings - Fork 2
/
ti-longjohn.js
169 lines (147 loc) · 4.7 KB
/
ti-longjohn.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
module.exports = function(global) {
var previous_trace = null;
var appDir = Ti.Filesystem.resourcesDirectory;
var exports = {
async_trace_limit: 10
}
var limit_frames = function(stack) {
if (exports.async_trace_limit <= 0) {
return;
}
var count = exports.async_trace_limit - 1;
var trace = stack;
while ((trace != null) && count > 1) {
trace = trace.__previous__;
--count;
}
if (trace != null) {
return delete trace.__previous__;
}
};
var collect_frames = function(stack) {
var trace = stack;
var frames = [trace.name + ' at ' + trace.sourceURL.replace(appDir, '') + ':' + trace.line];
while (trace != null) {
if (trace.__location__) {
frames.push('-------- ' + trace.__location__ + ' ---------');
}
var lines = trace.backtrace.split('\n');
lines = lines.filter(function (line) { return line.indexOf(__filename) === -1; });
lines = lines.map(function (line) { return line.replace(appDir, ''); });
frames = frames.concat(lines);
trace = trace.__previous__;
}
return frames;
};
var create_trace = function (location) {
try {
i.dont.exist();
}
catch (trace_error) {
trace_error.__location__ = location;
trace_error.__previous__ = previous_trace;
limit_frames(trace_error);
return trace_error;
}
};
var call_callback_with_trace = function(trace, callback, args) {
var old_previous_trace = previous_trace;
previous_trace = trace;
try {
return callback.apply(this, args);
} catch (_error) {
if (!_error.longjohn) {
_error.__previous__ = previous_trace;
_error.longjohn = collect_frames(_error);
_error.__previous__ = undefined;
}
throw _error;
} finally {
previous_trace = old_previous_trace;
}
};
var wrap_callback = function(callback, location) {
var trace = create_trace(location);
return function() {
return call_callback_with_trace(trace, callback, arguments);
};
};
// global entrypoints
var _setTimeout = global.setTimeout;
var _setInterval = global.setInterval;
global.setTimeout = function(callback) {
var args;
args = Array.prototype.slice.call(arguments);
args[0] = wrap_callback(callback, 'setTimeout');
return _setTimeout.apply(this, args);
};
global.setInterval = function(callback) {
var args;
args = Array.prototype.slice.call(arguments);
args[0] = wrap_callback(callback, 'setInterval');
return _setInterval.apply(this, args);
};
// setImmediate entrypoint – Not actually part of Titanium, but if some
// library implements it, we wrap it.
if (global.setImmediate != null) {
var _setImmediate = global.setImmediate;
global.setImmediate = function(callback) {
var args;
args = Array.prototype.slice.call(arguments);
args[0] = wrap_callback(callback, 'global.setImmediate');
return _setImmediate.apply(this, args);
};
}
// process entrypoints – not actually part of Titanium, but if some library
// like Ti.node.JS implements it, we wrap it.
try {
var process = require('process');
var _nextTick = process.nextTick;
var __nextDomainTick = process._nextDomainTick;
process.nextTick = function (callback) {
var args;
args = Array.prototype.slice.call(arguments);
args[0] = wrap_callback(callback, 'process.nextTick');
return _nextTick.apply(this, args);
};
process._nextDomainTick = function (callback) {
var args;
args = Array.prototype.slice.call(arguments);
args[0] = wrap_callback(callback, 'process._nextDomainTick');
return __nextDomainTick.apply(this, args);
};
}
catch (err) {
}
// library patch functions
exports.patch_async = function(async) {
var _queue = async.queue;
async.queue = function(worker, concurrency) {
// a worker which dewraps the task
var patched_worker = function(task, callback) {
return call_callback_with_trace(task.previous_trace, worker, [task.data, callback]);
};
var q = _queue(patched_worker, concurrency);
// async.push which wraps the task data
var _push = q.push;
q.push = function (data, callback) {
var trace = create_trace('async.queue.push');
return _push({
data: data,
previous_trace: trace
}, callback);
};
// async.unshift which wraps the task data
var _unshift = q.push;
q.unshift = function (data, callback) {
var trace = create_trace('async.queue.unshift');
return _unshift({
data: data,
previous_trace: trace
}, callback);
};
return q;
}
};
return exports;
};