squash_javascript 1.0.3 → 2.0.5
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.
- checksums.yaml +5 -13
- data/README.md +49 -8
- data/bin/upload_source_map +10 -4
- data/lib/squash/javascript/capistrano.rb +16 -0
- data/lib/squash/javascript/patches.rb +33 -0
- data/lib/squash/javascript/railtie.rb +5 -0
- data/lib/squash/javascript/source_mapping_coffeescript_template.rb +27 -0
- data/lib/squash/javascript/source_mapping_javascript_minifier.rb +36 -0
- data/lib/squash/javascript/tasks/sourcemaps.rake +73 -0
- data/lib/squash/javascript.rb +4 -1
- data/lib/tasks/squash.cap +30 -0
- data/vendor/assets/javascripts/squash_javascript/{client.coffee → client.js.coffee} +1 -1
- data/vendor/assets/javascripts/squash_javascript/tracekit.js +1000 -996
- data/vendor/assets/javascripts/squash_javascript.min.js +24 -24
- data/vendor/assets/javascripts/squash_javascript.orig.js +1 -1
- metadata +47 -29
- data/lib/squash/javascript/source_map.rb +0 -181
@@ -47,129 +47,132 @@ var TraceKit = {};
|
|
47
47
|
* TraceKit.computeStackTrace docs.
|
48
48
|
*/
|
49
49
|
TraceKit.report = (function () {
|
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
|
-
|
50
|
+
var handlers = [],
|
51
|
+
lastException = null,
|
52
|
+
lastExceptionStack = null;
|
53
|
+
|
54
|
+
/**
|
55
|
+
* Add a crash handler.
|
56
|
+
* @param {Function} handler
|
57
|
+
*/
|
58
|
+
function subscribe(handler) {
|
59
|
+
handlers.push(handler);
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* Remove a crash handler.
|
64
|
+
* @param {Function} handler
|
65
|
+
*/
|
66
|
+
function unsubscribe(handler) {
|
67
|
+
for (var i = handlers.length - 1; i >= 0; --i) {
|
68
|
+
if (handlers[i] === handler) {
|
69
|
+
handlers.splice(i, 1);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
/**
|
75
|
+
* Dispatch stack information to all handlers.
|
76
|
+
* @param {Object.<string, *>} stack
|
77
77
|
* @param {Error} e
|
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
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
78
|
+
*/
|
79
|
+
function notifyHandlers(stack, e) {
|
80
|
+
var exception = null;
|
81
|
+
for (var i in handlers) {
|
82
|
+
if (handlers.hasOwnProperty(i)) {
|
83
|
+
try {
|
84
|
+
handlers[i](stack, e);
|
85
|
+
}
|
86
|
+
catch (inner) {
|
87
|
+
exception = inner;
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
if (exception) {
|
93
|
+
throw exception;
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
var _oldOnerrorHandler = window.onerror;
|
98
|
+
|
99
|
+
/**
|
100
|
+
* Ensures all global unhandled exceptions are recorded.
|
101
|
+
* Supported by Gecko and IE.
|
102
|
+
* @param {string} message Error message.
|
103
|
+
* @param {string} url URL of script that generated the exception.
|
104
|
+
* @param {(number|string)} lineNo The line number at which the error
|
105
|
+
* occurred.
|
106
|
+
*/
|
107
|
+
window.onerror = function(message, url, lineNo, col, error) {
|
108
|
+
var stack = null;
|
109
|
+
var ex = null;
|
110
|
+
|
111
|
+
if (error) stack = TraceKit.computeStackTrace(error);
|
112
|
+
if (!stack) {
|
113
|
+
if (lastExceptionStack) {
|
114
|
+
TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(lastExceptionStack, url, lineNo, col, message);
|
115
|
+
stack = lastExceptionStack;
|
116
|
+
ex = lastException;
|
117
|
+
lastExceptionStack = null;
|
118
|
+
lastException = null;
|
119
|
+
}
|
120
|
+
else {
|
121
|
+
var location = { 'url': url, 'line': lineNo, 'column': col };
|
122
|
+
location.func = TraceKit.computeStackTrace.guessFunctionName(location.url, location.line);
|
123
|
+
location.context = TraceKit.computeStackTrace.gatherContext(location.url, location.line);
|
124
|
+
stack = { 'mode': 'onerror', 'message': message, 'stack': [ location ] };
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
128
|
+
notifyHandlers(stack, ex);
|
129
|
+
|
130
|
+
if (_oldOnerrorHandler) {
|
131
|
+
return _oldOnerrorHandler.apply(this, arguments);
|
132
|
+
}
|
133
|
+
|
134
|
+
return false;
|
135
|
+
};
|
136
|
+
|
137
|
+
/**
|
138
|
+
* Reports an unhandled Error to TraceKit.
|
139
|
+
* @param {Error} ex
|
140
|
+
*/
|
141
|
+
function report(ex) {
|
142
|
+
if (lastExceptionStack) {
|
143
|
+
if (lastException === ex) {
|
144
|
+
return; // already caught by an inner catch block, ignore
|
145
|
+
}
|
146
|
+
else {
|
147
|
+
var s = lastExceptionStack;
|
148
|
+
lastExceptionStack = null;
|
149
|
+
lastException = null;
|
150
|
+
notifyHandlers(s, ex);
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
var stack = TraceKit.computeStackTrace(ex);
|
155
|
+
lastExceptionStack = stack;
|
156
|
+
lastException = ex;
|
157
|
+
|
158
|
+
// If the stack trace is incomplete, wait for 2 seconds for
|
159
|
+
// slow slow IE to see if onerror occurs or not before reporting
|
160
|
+
// this exception; otherwise, we will end up with an incomplete
|
161
|
+
// stack trace
|
162
|
+
window.setTimeout(function () {
|
163
|
+
if (lastException === ex) {
|
164
|
+
lastExceptionStack = null;
|
165
|
+
lastException = null;
|
166
|
+
notifyHandlers(stack, ex);
|
167
|
+
}
|
168
|
+
}, (stack.incomplete ? 2000 : 0));
|
169
|
+
|
170
|
+
throw ex; // re-throw to propagate to the top level (and cause window.onerror)
|
171
|
+
}
|
172
|
+
|
173
|
+
report.subscribe = subscribe;
|
174
|
+
report.unsubscribe = unsubscribe;
|
175
|
+
return report;
|
173
176
|
}());
|
174
177
|
|
175
178
|
/**
|
@@ -240,727 +243,728 @@ TraceKit.report = (function () {
|
|
240
243
|
* }
|
241
244
|
*/
|
242
245
|
TraceKit.computeStackTrace = (function () {
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
246
|
+
var debug = false, sourceCache = {};
|
247
|
+
|
248
|
+
/**
|
249
|
+
* Attempts to retrieve source code via XMLHttpRequest, which is used
|
250
|
+
* to look up anonymous function names.
|
251
|
+
* @param {string} url URL of source code.
|
252
|
+
* @return {string} Source contents.
|
253
|
+
*/
|
254
|
+
function loadSource(url) {
|
255
|
+
try {
|
256
|
+
if (XMLHttpRequest === undefined) { // IE 5.x-6.x:
|
257
|
+
XMLHttpRequest = function () {
|
258
|
+
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch(e) {}
|
259
|
+
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch(e) {}
|
260
|
+
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch(e) {}
|
261
|
+
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) {}
|
262
|
+
throw new Error('No XHR.');
|
263
|
+
};
|
264
|
+
}
|
265
|
+
|
266
|
+
var request = new XMLHttpRequest();
|
267
|
+
request.open('GET', url, false);
|
268
|
+
request.send('');
|
269
|
+
return request.responseText;
|
270
|
+
}
|
271
|
+
catch (e) {
|
272
|
+
return '';
|
273
|
+
}
|
274
|
+
}
|
275
|
+
|
276
|
+
/**
|
277
|
+
* Retrieves source code from the source code cache.
|
278
|
+
* @param {string} url URL of source code.
|
279
|
+
* @return {Array.<string>} Source contents.
|
280
|
+
*/
|
281
|
+
function getSource(url) {
|
282
|
+
if (!sourceCache.hasOwnProperty(url)) {
|
283
|
+
// URL needs to be able to fetched within the acceptable domain. Otherwise,
|
284
|
+
// cross-domain errors will be triggered.
|
285
|
+
var source;
|
286
|
+
var urlTokens = url.split('/');
|
287
|
+
if (urlTokens.length > 2 && urlTokens[2] === document.domain) {
|
288
|
+
source = loadSource(url);
|
289
|
+
} else {
|
290
|
+
source = [];
|
291
|
+
}
|
292
|
+
sourceCache[url] = source.length ? source.split("\n") : [];
|
293
|
+
}
|
294
|
+
|
295
|
+
return sourceCache[url];
|
296
|
+
}
|
297
|
+
|
298
|
+
/**
|
299
|
+
* Tries to use an externally loaded copy of source code to determine
|
300
|
+
* the name of a function by looking at the name of the variable it was
|
301
|
+
* assigned to, if any.
|
302
|
+
* @param {string} url URL of source code.
|
303
|
+
* @param {(string|number)} lineNo Line number in source code.
|
304
|
+
* @return {string} The function name, if discoverable.
|
305
|
+
*/
|
306
|
+
function guessFunctionName(url, lineNo) {
|
307
|
+
var reFunctionArgNames = /function ([^(]*)\(([^)]*)\)/,
|
308
|
+
reGuessFunction = /['"]?([0-9A-Za-z$_]+)['"]?\s*[:=]\s*(function|eval|new Function)/,
|
309
|
+
line = '',
|
310
|
+
maxLines = 10,
|
311
|
+
source = getSource(url),
|
312
|
+
m;
|
313
|
+
|
314
|
+
if (!source.length) {
|
315
|
+
return '?';
|
316
|
+
}
|
317
|
+
|
318
|
+
// Walk backwards from the first line in the function until we find the line which
|
319
|
+
// matches the pattern above, which is the function definition
|
320
|
+
for (var i = 0; i < maxLines; ++i) {
|
321
|
+
line = source[lineNo - i] + line;
|
322
|
+
|
323
|
+
if (line !== undefined) {
|
324
|
+
if ((m = reGuessFunction.exec(line))) {
|
325
|
+
return m[1];
|
326
|
+
}
|
327
|
+
else if ((m = reFunctionArgNames.exec(line))) {
|
328
|
+
return m[1];
|
329
|
+
}
|
330
|
+
}
|
331
|
+
}
|
332
|
+
|
333
|
+
return '?';
|
334
|
+
}
|
335
|
+
|
336
|
+
/**
|
337
|
+
* Retrieves the surrounding lines from where an exception occurred.
|
338
|
+
* @param {string} url URL of source code.
|
339
|
+
* @param {(string|number)} line Line number in source code to centre
|
340
|
+
* around for context.
|
341
|
+
* @return {?Array.<string>} Lines of source code.
|
342
|
+
*/
|
343
|
+
function gatherContext(url, line) {
|
344
|
+
var source = getSource(url),
|
345
|
+
context = [],
|
346
|
+
hasContext = false;
|
347
|
+
|
348
|
+
if (!source.length) {
|
349
|
+
return null;
|
350
|
+
}
|
351
|
+
|
352
|
+
line -= 1; // convert to 0-based index
|
353
|
+
|
354
|
+
for (var i = line - 2, j = line + 2; i < j; ++i) {
|
355
|
+
context.push(source[i]);
|
356
|
+
if (source[i] !== undefined) {
|
357
|
+
hasContext = true;
|
358
|
+
}
|
359
|
+
}
|
360
|
+
|
361
|
+
return hasContext ? context : null;
|
362
|
+
}
|
363
|
+
|
364
|
+
/**
|
365
|
+
* Escapes special characters, except for whitespace, in a string to be
|
366
|
+
* used inside a regular expression as a string literal.
|
367
|
+
* @param {string} text The string.
|
368
|
+
* @return {string} The escaped string literal.
|
369
|
+
*/
|
370
|
+
function escapeRegExp(text) {
|
371
|
+
return text.replace(/[\-\[\]{}()*+?.,\\\^$|#]/g, '\\$&');
|
372
|
+
}
|
373
|
+
|
374
|
+
/**
|
375
|
+
* Escapes special characters in a string to be used inside a regular
|
376
|
+
* expression as a string literal. Also ensures that HTML entities will
|
377
|
+
* be matched the same as their literal friends.
|
378
|
+
* @param {string} body The string.
|
379
|
+
* @return {string} The escaped string.
|
380
|
+
*/
|
381
|
+
function escapeCodeAsRegExpForMatchingInsideHTML(body) {
|
382
|
+
return escapeRegExp(body).replace('<', '(?:<|<)').replace('>', '(?:>|>)')
|
383
|
+
.replace('&', '(?:&|&)').replace('"', '(?:"|")').replace(/\s+/g, '\\s+');
|
384
|
+
}
|
385
|
+
|
386
|
+
/**
|
387
|
+
* Determines where a code fragment occurs in the source code.
|
388
|
+
* @param {RegExp} re The function definition.
|
389
|
+
* @param {Array.<string>} urls A list of URLs to search.
|
390
|
+
* @return {?Object.<string, (string|number)>} An object containing
|
391
|
+
* the url, line, and column number of the defined function.
|
392
|
+
*/
|
393
|
+
function findSourceInUrls(re, urls) {
|
394
|
+
var source, m;
|
395
|
+
for (var i = 0, j = urls.length; i < j; ++i) {
|
396
|
+
// console.log('searching', urls[i]);
|
397
|
+
if ((source = getSource(urls[i])).length) {
|
398
|
+
source = source.join("\n");
|
399
|
+
if ((m = re.exec(source))) {
|
400
|
+
// console.log('Found function in ' + urls[i]);
|
401
|
+
|
402
|
+
return {
|
403
|
+
'url': urls[i],
|
404
|
+
'line': source.substring(0, m.index).split("\n").length,
|
405
|
+
'column': m.index - source.lastIndexOf("\n", m.index) - 1
|
406
|
+
};
|
407
|
+
}
|
408
|
+
}
|
409
|
+
}
|
410
|
+
|
411
|
+
// console.log('no match');
|
412
|
+
|
413
|
+
return null;
|
414
|
+
}
|
415
|
+
|
416
|
+
/**
|
417
|
+
* Determines at which column a code fragment occurs on a line of the
|
418
|
+
* source code.
|
419
|
+
* @param {string} fragment The code fragment.
|
420
|
+
* @param {string} url The URL to search.
|
421
|
+
* @param {(string|number)} line The line number to examine.
|
422
|
+
* @return {?number} The column number.
|
423
|
+
*/
|
424
|
+
function findSourceInLine(fragment, url, line) {
|
425
|
+
var source = getSource(url),
|
426
|
+
re = new RegExp('\\b' + escapeRegExp(fragment) + '\\b'),
|
427
|
+
m;
|
428
|
+
|
429
|
+
line -= 1;
|
430
|
+
|
431
|
+
if (source && source.length > line && (m = re.exec(source[line]))) {
|
432
|
+
return m.index;
|
433
|
+
}
|
434
|
+
|
435
|
+
return null;
|
436
|
+
}
|
437
|
+
|
438
|
+
/**
|
439
|
+
* Determines where a function was defined within the source code.
|
440
|
+
* @param {(Function|string)} func A function reference or serialized
|
441
|
+
* function definition.
|
442
|
+
* @return {?Object.<string, (string|number)>} An object containing
|
443
|
+
* the url, line, and column number of the defined function.
|
444
|
+
*/
|
445
|
+
function findSourceByFunctionBody(func) {
|
446
|
+
var urls = [ window.location.href ],
|
447
|
+
scripts = document.getElementsByTagName("script"),
|
448
|
+
body,
|
449
|
+
code = '' + func,
|
450
|
+
codeRE = /^function(?:\s+([\w$]+))?\s*\(([\w\s,]*)\)\s*\{\s*(\S[\s\S]*\S)\s*\}\s*$/,
|
451
|
+
eventRE = /^function on([\w$]+)\s*\(event\)\s*\{\s*(\S[\s\S]*\S)\s*\}\s*$/,
|
452
|
+
re,
|
453
|
+
parts,
|
454
|
+
result;
|
455
|
+
|
456
|
+
for (var i = 0; i < scripts.length; ++i) {
|
457
|
+
var script = scripts[i];
|
458
|
+
if (script.src) {
|
459
|
+
urls.push(script.src);
|
460
|
+
}
|
461
|
+
}
|
462
|
+
|
463
|
+
if (!(parts = codeRE.exec(code))) {
|
464
|
+
re = new RegExp(escapeRegExp(code).replace(/\s+/g, '\\s+'));
|
465
|
+
}
|
466
|
+
|
467
|
+
// not sure if this is really necessary, but I don’t have a test
|
468
|
+
// corpus large enough to confirm that and it was in the original.
|
469
|
+
else {
|
470
|
+
var name = parts[1] ? '\\s+' + parts[1] : '',
|
471
|
+
args = parts[2].split(",").join("\\s*,\\s*");
|
472
|
+
|
473
|
+
body = escapeRegExp(parts[3])
|
474
|
+
.replace(/;$/, ';?') // semicolon is inserted if the function ends with a comment
|
475
|
+
.replace(/\s+/g, '\\s+');
|
476
|
+
re = new RegExp("function" + name + "\\s*\\(\\s*" + args + "\\s*\\)\\s*{\\s*" + body + "\\s*}");
|
477
|
+
}
|
478
|
+
|
479
|
+
// look for a normal function definition
|
480
|
+
if ((result = findSourceInUrls(re, urls))) {
|
481
|
+
return result;
|
482
|
+
}
|
483
|
+
|
484
|
+
// look for an old-school event handler function
|
485
|
+
if ((parts = eventRE.exec(code))) {
|
486
|
+
var event = parts[1];
|
487
|
+
body = escapeCodeAsRegExpForMatchingInsideHTML(parts[2]);
|
488
|
+
|
489
|
+
// look for a function defined in HTML as an onXXX handler
|
490
|
+
re = new RegExp("on" + event + '=[\\\'"]\\s*' + body + '\\s*[\\\'"]', 'i');
|
491
|
+
|
492
|
+
if ((result = findSourceInUrls(re, urls[0]))) {
|
493
|
+
return result;
|
494
|
+
}
|
495
|
+
|
496
|
+
// look for ???
|
497
|
+
re = new RegExp(body);
|
498
|
+
|
499
|
+
if ((result = findSourceInUrls(re, urls))) {
|
500
|
+
return result;
|
501
|
+
}
|
502
|
+
}
|
503
|
+
|
504
|
+
return null;
|
505
|
+
}
|
506
|
+
|
507
|
+
// Contents of Exception in various browsers.
|
508
|
+
//
|
509
|
+
// SAFARI:
|
510
|
+
// ex.message = Can't find variable: qq
|
511
|
+
// ex.line = 59
|
512
|
+
// ex.sourceId = 580238192
|
513
|
+
// ex.sourceURL = http://...
|
514
|
+
// ex.expressionBeginOffset = 96
|
515
|
+
// ex.expressionCaretOffset = 98
|
516
|
+
// ex.expressionEndOffset = 98
|
517
|
+
// ex.name = ReferenceError
|
518
|
+
//
|
519
|
+
// FIREFOX:
|
520
|
+
// ex.message = qq is not defined
|
521
|
+
// ex.fileName = http://...
|
522
|
+
// ex.lineNumber = 59
|
523
|
+
// ex.stack = ...stack trace... (see the example below)
|
524
|
+
// ex.name = ReferenceError
|
525
|
+
//
|
526
|
+
// CHROME:
|
527
|
+
// ex.message = qq is not defined
|
528
|
+
// ex.name = ReferenceError
|
529
|
+
// ex.type = not_defined
|
530
|
+
// ex.arguments = ['aa']
|
531
|
+
// ex.stack = ...stack trace...
|
532
|
+
//
|
533
|
+
// INTERNET EXPLORER:
|
534
|
+
// ex.message = ...
|
535
|
+
// ex.name = ReferenceError
|
536
|
+
//
|
537
|
+
// OPERA:
|
538
|
+
// ex.message = ...message... (see the example below)
|
539
|
+
// ex.name = ReferenceError
|
540
|
+
// ex.opera#sourceloc = 11 (pretty much useless, duplicates the info in ex.message)
|
541
|
+
// ex.stacktrace = n/a; see 'opera:config#UserPrefs|Exceptions Have Stacktrace'
|
542
|
+
|
543
|
+
/**
|
544
|
+
* Computes stack trace information from the stack property.
|
545
|
+
* Chrome and Gecko use this property.
|
546
|
+
* @param {Error} ex
|
547
|
+
* @return {?Object.<string, *>} Stack trace information.
|
548
|
+
*/
|
549
|
+
function computeStackTraceFromStackProp(ex) {
|
550
|
+
if (!ex.stack) {
|
551
|
+
return null;
|
552
|
+
}
|
553
|
+
|
554
|
+
var chrome = /^\s*at (?:((?:\[object object\])?\S+(?: \[as \S+\])?) )?\(?((?:file|http|https):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
|
555
|
+
gecko = /^\s*(?:(\S*)(?:\((.*?)\))?@)?((?:file|http|https).*?):(\d+)(?::(\d+))?\s*$/i,
|
556
|
+
lines = ex.stack.split("\n"),
|
557
|
+
stack = [],
|
558
|
+
parts,
|
559
|
+
element,
|
560
|
+
reference = /^(.*) is undefined$/.exec(ex.message);
|
561
|
+
|
562
|
+
for (var i = 0, j = lines.length; i < j; ++i) {
|
563
|
+
if ((parts = gecko.exec(lines[i]))) {
|
564
|
+
element = { 'url': parts[3], 'func': parts[1], 'args': parts[2] ? parts[2].split(',') : '', 'line': +parts[4], 'column': parts[5] ? +parts[5] : null };
|
565
|
+
}
|
566
|
+
else if ((parts = chrome.exec(lines[i]))) {
|
567
|
+
element = { 'url': parts[2], 'func': parts[1], 'line': +parts[3], 'column': parts[4] ? +parts[4] : null };
|
568
|
+
}
|
569
|
+
else {
|
570
|
+
continue;
|
571
|
+
}
|
572
|
+
|
573
|
+
if (!element.func && element.line) {
|
574
|
+
element.func = guessFunctionName(element.url, element.line);
|
575
|
+
}
|
576
|
+
|
577
|
+
if (element.line) {
|
578
|
+
element.context = gatherContext(element.url, element.line);
|
579
|
+
}
|
580
|
+
|
581
|
+
stack.push(element);
|
582
|
+
}
|
583
|
+
|
584
|
+
if (stack[0] && stack[0].line && !stack[0].column && reference) {
|
585
|
+
stack[0].column = findSourceInLine(reference[1], stack[0].url, stack[0].line);
|
586
|
+
}
|
587
|
+
|
588
|
+
if (!stack.length) {
|
589
|
+
return null;
|
590
|
+
}
|
591
|
+
|
592
|
+
return {
|
593
|
+
'mode': 'stack',
|
594
|
+
'name': ex.name,
|
595
|
+
'message': ex.message,
|
596
|
+
'stack': stack
|
597
|
+
};
|
598
|
+
}
|
599
|
+
|
600
|
+
/**
|
601
|
+
* Computes stack trace information from the stacktrace property.
|
602
|
+
* Opera 10 uses this property.
|
603
|
+
* @param {Error} ex
|
604
|
+
* @return {?Object.<string, *>} Stack trace information.
|
605
|
+
*/
|
606
|
+
function computeStackTraceFromStacktraceProp(ex) {
|
607
|
+
// Access and store the stacktrace property before doing ANYTHING
|
608
|
+
// else to it because Opera is not very good at providing it
|
609
|
+
// reliably in other circumstances.
|
610
|
+
var stacktrace = ex.stacktrace;
|
611
|
+
|
612
|
+
var testRE = / line (\d+), column (\d+) in (?:<anonymous function: ([^>]+)>|([^\)]+))\((.*)\) in (.*):\s*$/i,
|
613
|
+
lines = stacktrace.split("\n"),
|
614
|
+
stack = [],
|
615
|
+
parts;
|
616
|
+
|
617
|
+
for (var i = 0, j = lines.length; i < j; i += 2) {
|
618
|
+
if ((parts = testRE.exec(lines[i]))) {
|
619
|
+
var element = { 'line': +parts[1], 'column': +parts[2], 'func': parts[3] || parts[4], 'args': parts[5] ? parts[5].split(',') : [], 'url': parts[6] };
|
620
|
+
|
621
|
+
if (!element.func && element.line) {
|
622
|
+
element.func = guessFunctionName(element.url, element.line);
|
623
|
+
}
|
624
|
+
if (element.line) {
|
625
|
+
try {
|
626
|
+
element.context = gatherContext(element.url, element.line);
|
627
|
+
}
|
628
|
+
catch (exc) {}
|
629
|
+
}
|
630
|
+
|
631
|
+
if (!element.context) {
|
632
|
+
element.context = [ lines[i + 1] ];
|
633
|
+
}
|
634
|
+
|
635
|
+
stack.push(element);
|
636
|
+
}
|
637
|
+
}
|
638
|
+
|
639
|
+
if (!stack.length) {
|
640
|
+
return null;
|
641
|
+
}
|
642
|
+
|
643
|
+
return {
|
644
|
+
'mode': 'stacktrace',
|
645
|
+
'name': ex.name,
|
646
|
+
'message': ex.message,
|
647
|
+
'stack': stack
|
648
|
+
};
|
649
|
+
}
|
650
|
+
|
651
|
+
/**
|
652
|
+
* NOT TESTED.
|
653
|
+
* Computes stack trace information from an error message that includes
|
654
|
+
* the stack trace.
|
655
|
+
* Opera 9 and earlier use this method if the option to show stack
|
656
|
+
* traces is turned on in opera:config.
|
657
|
+
* @param {Error} ex
|
658
|
+
* @return {?Object.<string, *>} Stack information.
|
659
|
+
*/
|
660
|
+
function computeStackTraceFromOperaMultiLineMessage(ex) {
|
661
|
+
// Opera includes a stack trace into the exception message. An example is:
|
662
|
+
//
|
663
|
+
// Statement on line 3: Undefined variable: undefinedFunc
|
664
|
+
// Backtrace:
|
665
|
+
// Line 3 of linked script file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.js: In function zzz
|
666
|
+
// undefinedFunc(a);
|
667
|
+
// Line 7 of inline#1 script in file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.html: In function yyy
|
668
|
+
// zzz(x, y, z);
|
669
|
+
// Line 3 of inline#1 script in file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.html: In function xxx
|
670
|
+
// yyy(a, a, a);
|
671
|
+
// Line 1 of function script
|
672
|
+
// try { xxx('hi'); return false; } catch(ex) { TraceKit.report(ex); }
|
673
|
+
// ...
|
674
|
+
|
675
|
+
var lines = ex.message.split('\n');
|
676
|
+
if (lines.length < 4) {
|
677
|
+
return null;
|
678
|
+
}
|
679
|
+
|
680
|
+
var lineRE1 = /^\s*Line (\d+) of linked script ((?:file|https?)\S+)(?:: in function (\S+))?\s*$/i,
|
681
|
+
lineRE2 = /^\s*Line (\d+) of inline#(\d+) script in ((?:file|https?)\S+)(?:: in function (\S+))?\s*$/i,
|
682
|
+
lineRE3 = /^\s*Line (\d+) of function script\s*$/i,
|
683
|
+
stack = [],
|
684
|
+
scripts = document.getElementsByTagName('script'),
|
685
|
+
inlineScriptBlocks = [],
|
686
|
+
parts,
|
687
|
+
i,
|
688
|
+
len,
|
689
|
+
source;
|
690
|
+
|
691
|
+
for (i in scripts) {
|
692
|
+
if (scripts.hasOwnProperty(i) && !scripts[i].src) {
|
693
|
+
inlineScriptBlocks.push(scripts[i]);
|
694
|
+
}
|
695
|
+
}
|
696
|
+
|
697
|
+
for (i = 2, len = lines.length; i < len; i += 2) {
|
698
|
+
var item = null;
|
699
|
+
if ((parts = lineRE1.exec(lines[i]))) {
|
700
|
+
item = { 'url': parts[2], 'func': parts[3], 'line': +parts[1] };
|
701
|
+
}
|
702
|
+
else if ((parts = lineRE2.exec(lines[i]))) {
|
703
|
+
item = { 'url': parts[3], 'func': parts[4] };
|
704
|
+
var relativeLine = (+parts[1]); // relative to the start of the <SCRIPT> block
|
705
|
+
var script = inlineScriptBlocks[parts[2] - 1];
|
706
|
+
if (script) {
|
707
|
+
source = getSource(item.url);
|
708
|
+
if (source) {
|
709
|
+
source = source.join("\n");
|
710
|
+
var pos = source.indexOf(script.innerText);
|
711
|
+
if (pos >= 0) {
|
712
|
+
item.line = relativeLine + source.substring(0, pos).split("\n").length;
|
713
|
+
}
|
714
|
+
}
|
715
|
+
}
|
716
|
+
}
|
717
|
+
else if ((parts = lineRE3.exec(lines[i]))) {
|
718
|
+
var url = window.location.href.replace(/#.*$/, ''), line = parts[1];
|
719
|
+
var re = new RegExp(escapeCodeAsRegExpForMatchingInsideHTML(lines[i + 1]));
|
720
|
+
source = findSourceInUrls(re, [url]);
|
721
|
+
item = { 'url': url, 'line': source ? source.line : line, 'func': '' };
|
722
|
+
}
|
723
|
+
|
724
|
+
if (item) {
|
725
|
+
if (!item.func) {
|
726
|
+
item.func = guessFunctionName(item.url, item.line);
|
727
|
+
}
|
728
|
+
var context = gatherContext(item.url, item.line);
|
729
|
+
var midline = (context ? context[Math.floor(context.length / 2)] : null);
|
730
|
+
if (context && midline.replace(/^\s*/, '') === lines[i + 1].replace(/^\s*/, '')) {
|
731
|
+
item.context = context;
|
732
|
+
}
|
733
|
+
else {
|
734
|
+
// if (context) alert("Context mismatch. Correct midline:\n" + lines[i+1] + "\n\nMidline:\n" + midline + "\n\nContext:\n" + context.join("\n") + "\n\nURL:\n" + item.url);
|
735
|
+
item.context = [lines[i + 1]];
|
736
|
+
}
|
737
|
+
stack.push(item);
|
738
|
+
}
|
739
|
+
}
|
740
|
+
if (!stack.length) {
|
741
|
+
return null; // could not parse multiline exception message as Opera stack trace
|
742
|
+
}
|
743
|
+
|
744
|
+
return {
|
745
|
+
'mode': 'multiline',
|
746
|
+
'name': ex.name,
|
747
|
+
'message': lines[0],
|
748
|
+
'stack': stack
|
749
|
+
};
|
750
|
+
}
|
751
|
+
|
752
|
+
/**
|
753
|
+
* Adds information about the first frame to incomplete stack traces.
|
754
|
+
* Safari and IE require this to get complete data on the first frame.
|
755
|
+
* @param {Object.<string, *>} stackInfo Stack trace information from
|
756
|
+
* one of the compute* methods.
|
757
|
+
* @param {string} url The URL of the script that caused an error.
|
758
|
+
* @param {(number|string)} lineNo The line number of the script that
|
759
|
+
* caused an error.
|
760
|
+
* @param {string=} message The error generated by the browser, which
|
761
|
+
* hopefully contains the name of the object that caused the error.
|
762
|
+
* @return {boolean} Whether or not the stack information was
|
763
|
+
* augmented.
|
764
|
+
*/
|
765
|
+
function augmentStackTraceWithInitialElement(stackInfo, url, lineNo, col, message) {
|
766
|
+
var initial = {
|
767
|
+
'url': url,
|
768
|
+
'line': lineNo,
|
769
|
+
'column': message
|
770
|
+
};
|
771
|
+
|
772
|
+
if (initial.url && initial.line) {
|
773
|
+
stackInfo.incomplete = false;
|
774
|
+
|
775
|
+
if (!initial.func) {
|
776
|
+
initial.func = guessFunctionName(initial.url, initial.line);
|
777
|
+
}
|
778
|
+
|
779
|
+
if (!initial.context) {
|
780
|
+
initial.context = gatherContext(initial.url, initial.line);
|
781
|
+
}
|
782
|
+
|
783
|
+
var reference = / '([^']+)' /.exec(message);
|
784
|
+
if (reference) {
|
785
|
+
initial.column = findSourceInLine(reference[1], initial.url, initial.line);
|
786
|
+
}
|
787
|
+
|
788
|
+
if (stackInfo.stack.length > 0) {
|
789
|
+
if (stackInfo.stack[0].url === initial.url) {
|
790
|
+
if (stackInfo.stack[0].line === initial.line) {
|
791
|
+
return false; // already in stack trace
|
792
|
+
}
|
793
|
+
else if (!stackInfo.stack[0].line && stackInfo.stack[0].func === initial.func) {
|
794
|
+
stackInfo.stack[0].line = initial.line;
|
795
|
+
stackInfo.stack[0].context = initial.context;
|
796
|
+
return false;
|
797
|
+
}
|
798
|
+
}
|
799
|
+
}
|
800
|
+
|
801
|
+
stackInfo.stack.unshift(initial);
|
802
|
+
stackInfo.partial = true;
|
803
|
+
return true;
|
804
|
+
}
|
805
|
+
else {
|
806
|
+
stackInfo.incomplete = true;
|
807
|
+
}
|
808
|
+
|
809
|
+
return false;
|
810
|
+
}
|
811
|
+
|
812
|
+
/**
|
813
|
+
* Computes stack trace information by walking the arguments.caller
|
814
|
+
* chain at the time the exception occurred. This will cause earlier
|
815
|
+
* frames to be missed but is the only way to get any stack trace in
|
816
|
+
* Safari and IE. The top frame is restored by
|
817
|
+
* {@link augmentStackTraceWithInitialElement}.
|
818
|
+
* @param {Error} ex
|
819
|
+
* @return {?Object.<string, *>} Stack trace information.
|
820
|
+
*/
|
821
|
+
function computeStackTraceByWalkingCallerChain(ex, depth) {
|
822
|
+
var functionName = /function\s+([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)?\s*\(/i,
|
823
|
+
stack = [],
|
824
|
+
funcs = {},
|
825
|
+
recursion = false,
|
826
|
+
parts,
|
827
|
+
item,
|
828
|
+
source;
|
829
|
+
|
830
|
+
for (var curr = arguments.callee.caller; curr && !recursion; curr = curr.caller) {
|
831
|
+
if (curr === computeStackTrace || curr === TraceKit.report) {
|
832
|
+
// console.log('skipping internal function');
|
833
|
+
continue;
|
834
|
+
}
|
835
|
+
|
836
|
+
item = {
|
837
|
+
'url': null,
|
838
|
+
'func': '?',
|
839
|
+
'line': null,
|
840
|
+
'column': null
|
841
|
+
};
|
842
|
+
|
843
|
+
if (curr.name) {
|
844
|
+
item.func = curr.name;
|
845
|
+
}
|
846
|
+
else if ((parts = functionName.exec(curr.toString()))) {
|
847
|
+
item.func = parts[1];
|
848
|
+
}
|
849
|
+
|
850
|
+
if ((source = findSourceByFunctionBody(curr))) {
|
851
|
+
item.url = source.url;
|
852
|
+
item.line = source.line;
|
853
|
+
|
854
|
+
if (item.func === '?') {
|
855
|
+
item.func = guessFunctionName(item.url, item.line);
|
856
|
+
}
|
857
|
+
|
858
|
+
var reference = / '([^']+)' /.exec(ex.message || ex.description);
|
859
|
+
if (reference) {
|
860
|
+
item.column = findSourceInLine(reference[1], source.url, source.line);
|
861
|
+
}
|
862
|
+
}
|
863
|
+
|
864
|
+
if (funcs['' + curr]) {
|
865
|
+
item.recursion = true;
|
866
|
+
}
|
867
|
+
|
868
|
+
stack.push(item);
|
869
|
+
}
|
870
|
+
|
871
|
+
if (depth) {
|
872
|
+
// console.log('depth is ' + depth);
|
873
|
+
// console.log('stack is ' + stack.length);
|
874
|
+
stack.splice(0, depth);
|
875
|
+
}
|
876
|
+
|
877
|
+
var result = { 'mode': 'callers', 'name': ex.name, 'message': ex.message, 'stack': stack };
|
878
|
+
augmentStackTraceWithInitialElement(result, ex.sourceURL || ex.fileName, ex.line || ex.lineNumber, ex.message || ex.description);
|
879
|
+
return result;
|
880
|
+
}
|
881
|
+
|
882
|
+
/**
|
883
|
+
* Computes a stack trace for an exception.
|
884
|
+
* @param {Error} ex
|
885
|
+
* @param {(string|number)=} depth
|
886
|
+
*/
|
887
|
+
function computeStackTrace(ex, depth) {
|
888
|
+
var stack = null;
|
889
|
+
depth = (depth === undefined ? 0 : +depth);
|
890
|
+
|
891
|
+
try {
|
892
|
+
// This must be tried first because Opera 10 *destroys*
|
893
|
+
// its stacktrace property if you try to access the stack
|
894
|
+
// property first!!
|
895
|
+
stack = computeStackTraceFromStacktraceProp(ex);
|
896
|
+
if (stack) {
|
897
|
+
return stack;
|
898
|
+
}
|
899
|
+
}
|
900
|
+
catch (e) {
|
901
|
+
if (debug) {
|
902
|
+
throw e;
|
903
|
+
}
|
904
|
+
}
|
905
|
+
|
906
|
+
try {
|
907
|
+
stack = computeStackTraceFromStackProp(ex);
|
908
|
+
if (stack) {
|
909
|
+
return stack;
|
910
|
+
}
|
911
|
+
}
|
912
|
+
catch (e) {
|
913
|
+
if (debug) {
|
914
|
+
throw e;
|
915
|
+
}
|
916
|
+
}
|
917
|
+
|
918
|
+
try {
|
919
|
+
stack = computeStackTraceFromOperaMultiLineMessage(ex);
|
920
|
+
if (stack) {
|
921
|
+
return stack;
|
922
|
+
}
|
923
|
+
}
|
924
|
+
catch (e) {
|
925
|
+
if (debug) {
|
926
|
+
throw e;
|
927
|
+
}
|
928
|
+
}
|
929
|
+
|
930
|
+
try {
|
931
|
+
stack = computeStackTraceByWalkingCallerChain(ex, depth + 1);
|
932
|
+
if (stack) {
|
933
|
+
return stack;
|
934
|
+
}
|
935
|
+
}
|
936
|
+
catch (e) {
|
937
|
+
if (debug) {
|
938
|
+
throw e;
|
939
|
+
}
|
940
|
+
}
|
941
|
+
|
942
|
+
return { 'mode': 'failed' };
|
943
|
+
}
|
944
|
+
|
945
|
+
/**
|
946
|
+
* Logs a stacktrace starting from the previous call and working down.
|
947
|
+
* @param {(number|string)=} depth How many frames deep to trace.
|
948
|
+
* @return {Object.<string, *>} Stack trace information.
|
949
|
+
*/
|
950
|
+
function computeStackTraceOfCaller(depth) {
|
951
|
+
depth = (depth === undefined ? 0 : +depth) + 1; // "+ 1" because "ofCaller" should drop one frame
|
952
|
+
try {
|
953
|
+
(0)();
|
954
|
+
}
|
955
|
+
catch (ex) {
|
956
|
+
return computeStackTrace(ex, depth + 1);
|
957
|
+
}
|
958
|
+
|
959
|
+
return null;
|
960
|
+
}
|
961
|
+
|
962
|
+
computeStackTrace.augmentStackTraceWithInitialElement = augmentStackTraceWithInitialElement;
|
963
|
+
computeStackTrace.guessFunctionName = guessFunctionName;
|
964
|
+
computeStackTrace.gatherContext = gatherContext;
|
965
|
+
computeStackTrace.ofCaller = computeStackTraceOfCaller;
|
966
|
+
|
967
|
+
return computeStackTrace;
|
964
968
|
}());
|
965
969
|
|
966
970
|
/**
|
@@ -968,46 +972,46 @@ TraceKit.computeStackTrace = (function () {
|
|
968
972
|
* functions.
|
969
973
|
*/
|
970
974
|
(function (w) {
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
975
|
+
var slice = Array.prototype.slice,
|
976
|
+
_oldSetTimeout = w.setTimeout;
|
977
|
+
|
978
|
+
w.setTimeout = function () {
|
979
|
+
var args = slice.call(arguments, 0),
|
980
|
+
_oldCallback = args[0];
|
981
|
+
|
982
|
+
args[0] = function () {
|
983
|
+
try {
|
984
|
+
_oldCallback.apply(this, arguments);
|
985
|
+
}
|
986
|
+
catch (e) {
|
987
|
+
TraceKit.report(e);
|
988
|
+
throw e;
|
989
|
+
}
|
990
|
+
};
|
991
|
+
|
992
|
+
return _oldSetTimeout.apply(this, args);
|
993
|
+
};
|
994
|
+
|
995
|
+
// If you are reading this, you should know that setInterval is
|
996
|
+
// bad! Don’t use it!
|
997
|
+
// http://zetafleet.com/blog/why-i-consider-setinterval-harmful
|
998
|
+
var _oldSetInterval = w.setInterval;
|
999
|
+
w.setInterval = function () {
|
1000
|
+
var args = slice.call(arguments, 0),
|
1001
|
+
_oldCallback = args[0];
|
1002
|
+
|
1003
|
+
args[0] = function () {
|
1004
|
+
try {
|
1005
|
+
_oldCallback.apply(this, arguments);
|
1006
|
+
}
|
1007
|
+
catch (e) {
|
1008
|
+
TraceKit.report(e);
|
1009
|
+
throw e;
|
1010
|
+
}
|
1011
|
+
};
|
1012
|
+
|
1013
|
+
return _oldSetInterval.apply(this, args);
|
1014
|
+
};
|
1011
1015
|
}(window));
|
1012
1016
|
|
1013
1017
|
/**
|
@@ -1018,118 +1022,118 @@ TraceKit.computeStackTrace = (function () {
|
|
1018
1022
|
/* HACK - disabled because it causes inexplicable behavior
|
1019
1023
|
(function ($) {
|
1020
1024
|
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1025
|
+
// quit if jQuery isn't on the page
|
1026
|
+
if (!$) {
|
1027
|
+
return;
|
1028
|
+
}
|
1029
|
+
|
1030
|
+
var _oldEventAdd = $.event.add;
|
1031
|
+
$.event.add = function (elem, types, handler, data) {
|
1032
|
+
var _handler;
|
1033
|
+
|
1034
|
+
if (handler.handler) {
|
1035
|
+
_handler = handler.handler;
|
1036
|
+
handler.handler = function () {
|
1037
|
+
try {
|
1038
|
+
return _handler.apply(this, arguments);
|
1039
|
+
}
|
1040
|
+
catch (e) {
|
1041
|
+
TraceKit.report(e);
|
1042
|
+
throw e;
|
1043
|
+
}
|
1044
|
+
};
|
1045
|
+
}
|
1046
|
+
else {
|
1047
|
+
_handler = handler;
|
1048
|
+
handler = function () {
|
1049
|
+
try {
|
1050
|
+
return _handler.apply(this, arguments);
|
1051
|
+
}
|
1052
|
+
catch (e) {
|
1053
|
+
TraceKit.report(e);
|
1054
|
+
throw e;
|
1055
|
+
}
|
1056
|
+
};
|
1057
|
+
}
|
1058
|
+
|
1059
|
+
// If the handler we are attaching doesn’t have the same guid as
|
1060
|
+
// the original, it will never be removed when someone tries to
|
1061
|
+
// unbind the original function later. Technically as a result of
|
1062
|
+
// this our guids are no longer globally unique, but whatever, that
|
1063
|
+
// never hurt anybody RIGHT?!
|
1064
|
+
if (_handler.guid) {
|
1065
|
+
handler.guid = _handler.guid;
|
1066
|
+
}
|
1067
|
+
else {
|
1068
|
+
handler.guid = _handler.guid = $.guid++;
|
1069
|
+
}
|
1070
|
+
|
1071
|
+
return _oldEventAdd.call(this, elem, types, handler, data);
|
1072
|
+
};
|
1073
|
+
|
1074
|
+
var _oldReady = $.fn.ready;
|
1075
|
+
$.fn.ready = function (fn) {
|
1076
|
+
var _fn = function () {
|
1077
|
+
try {
|
1078
|
+
return fn.apply(this, arguments);
|
1079
|
+
}
|
1080
|
+
catch (e) {
|
1081
|
+
TraceKit.report(e);
|
1082
|
+
throw e;
|
1083
|
+
}
|
1084
|
+
};
|
1085
|
+
|
1086
|
+
return _oldReady.call(this, _fn);
|
1087
|
+
};
|
1088
|
+
|
1089
|
+
var _oldAjax = $.ajax;
|
1090
|
+
$.fn.ajax = function (s) {
|
1091
|
+
if ($.isFunction(s.complete)) {
|
1092
|
+
var _oldComplete = s.complete;
|
1093
|
+
s.complete = function () {
|
1094
|
+
try {
|
1095
|
+
return _oldComplete.apply(this, arguments);
|
1096
|
+
}
|
1097
|
+
catch (e) {
|
1098
|
+
TraceKit.report(e);
|
1099
|
+
throw e;
|
1100
|
+
}
|
1101
|
+
};
|
1102
|
+
}
|
1103
|
+
|
1104
|
+
if ($.isFunction(s.error)) {
|
1105
|
+
var _oldError = s.error;
|
1106
|
+
s.error = function () {
|
1107
|
+
try {
|
1108
|
+
return _oldError.apply(this, arguments);
|
1109
|
+
}
|
1110
|
+
catch (e) {
|
1111
|
+
TraceKit.report(e);
|
1112
|
+
throw e;
|
1113
|
+
}
|
1114
|
+
};
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
if ($.isFunction(s.success)) {
|
1118
|
+
var _oldSuccess = s.success;
|
1119
|
+
s.success = function () {
|
1120
|
+
try {
|
1121
|
+
return _oldSuccess.apply(this, arguments);
|
1122
|
+
}
|
1123
|
+
catch (e) {
|
1124
|
+
TraceKit.report(e);
|
1125
|
+
throw e;
|
1126
|
+
}
|
1127
|
+
};
|
1128
|
+
}
|
1129
|
+
|
1130
|
+
try {
|
1131
|
+
return _oldAjax.call(this, s);
|
1132
|
+
}
|
1133
|
+
catch (e) {
|
1134
|
+
TraceKit.report(e);
|
1135
|
+
throw e;
|
1136
|
+
}
|
1137
|
+
};
|
1134
1138
|
}(window.jQuery));
|
1135
1139
|
*/
|