Browse Source

Merge pull request #59 from gmetais/phantomas1.10

Phantomas1.10
Gaël Métais 10 years ago
parent
commit
79c387ba45

+ 13 - 0
front/src/views/rule.html

@@ -62,6 +62,19 @@
                         </div>
                     </div>
 
+                    <div ng-if="policyName === 'documentWriteCalls'">
+                        <b>{{offender.writeFn}}</b>
+                        <span ng-if="offender.from">
+                            called from
+                            <span ng-if="offender.from.functionName">{{offender.from.functionName}}()</span>
+                            <url-link url="offender.from.file" max-length="50"></url-link>
+                            line {{offender.from.line}}
+                        </span>
+                        <span ng-if="!offender.from">
+                            called from (no backtrace available)
+                        </span>
+                    </div>
+
                     <div ng-if="policyName === 'cssParsingErrors'">
                         <b>{{offender.error}}</b>
                         <file-and-line file="offender.file" line="offender.line" column="offender.column"></file-and-line>

+ 43 - 1
lib/metadata/policies.js

@@ -242,7 +242,49 @@ var policies = {
         "isOkThreshold": 0,
         "isBadThreshold": 10,
         "isAbnormalThreshold": 20,
-        "hasOffenders": false
+        "hasOffenders": true,
+        "offendersTransformFn": function(offenders) {
+            return {
+                count: offenders.length,
+                list: offenders.map(function(offender) {
+                    var parts = /^document.write(ln)?\(\) used from (.*)$/.exec(offender);
+
+                    if (parts) {
+
+                        var writeFn = 'document.write' + (parts[1] || '');
+
+                        var methodParts = /^([^\s]+) \((.+):(\d+)\)$/.exec(parts[2]);
+                        if (methodParts) {
+                            return {
+                                writeFn: writeFn,
+                                from: {
+                                    functionName: methodParts[1],
+                                    file: methodParts[2],
+                                    line: methodParts[3]
+                                }
+                            };
+                        } else {
+                            var noMethodParts = /^(.+):(\d+)$/.exec(parts[2]);
+
+                            if (noMethodParts) {
+                                return {
+                                    writeFn: writeFn,
+                                    from: {
+                                        file: noMethodParts[1],
+                                        line: noMethodParts[2]
+                                    }
+                                };
+                            }
+                        }
+                    }
+
+                    debug('documentWriteCalls offenders transform function error with "%s"', offender);
+                    return {
+                        parseError: offender
+                    };
+                })
+            };
+        }
     },
     "consoleMessages": {
         "tool": "phantomas",

+ 1 - 1
lib/tools/phantomas/custom_modules/core/scopeYLT/scopeYLT.js

@@ -36,7 +36,7 @@ exports.module = function(phantomas) {
                     phantomas.log('Overwritting phantomas spy function');
 
                     function spy(obj, fn, callbackBefore, callbackAfter) {
-                        var origFn = obj[fn];
+                        var origFn = obj && obj[fn];
 
                         if (typeof origFn !== 'function') {
                             return false;

+ 0 - 79
lib/tools/phantomas/custom_modules/modules/cachYLT/cachYLT.js

@@ -1,79 +0,0 @@
-/**
- * Analyzes HTTP caching headers
- *
- * @see https://developers.google.com/speed/docs/best-practices/caching
- */
-
-exports.version = '0.2.a';
-
-exports.module = function(phantomas) {
-    'use strict';
-    
-    var cacheControlRegExp = /max-age=(\d+)/;
-
-    function getCachingTime(url, headers) {
-        // false means "no caching"
-        var ttl = false,
-            headerName,
-            now = new Date(),
-            headerDate;
-
-        for (headerName in headers) {
-            var value = headers[headerName];
-
-            switch (headerName.toLowerCase()) {
-                // parse max-age=...
-                //
-                // max-age=2592000
-                // public, max-age=300, must-revalidate
-                case 'cache-control':
-                    var matches = value.match(cacheControlRegExp);
-
-                    if (matches) {
-                        ttl = parseInt(matches[1], 10);
-                    }
-                    break;
-
-                    // catch Expires and Pragma headers
-                case 'expires':
-                case 'pragma':
-                    // and Varnish specific headers
-                case 'x-pass-expires':
-                case 'x-pass-cache-control':
-                    phantomas.incrMetric('oldCachingHeaders'); // @desc number of responses with old, HTTP 1.0 caching headers (Expires and Pragma)
-                    phantomas.addOffender('oldCachingHeaders', url + ' - ' + headerName + ': ' + value);
-                    headerDate = Date.parse(value);
-                    if (headerDate) ttl = Math.round((headerDate - now) / 1000);
-                    break;
-            }
-        }
-
-        //console.log(JSON.stringify(headers)); console.log("TTL: " + ttl + ' s');
-
-        return ttl;
-    }
-
-    phantomas.setMetric('cachingNotSpecified'); // @desc number of responses with no caching header sent (no Cache-Control header)
-    phantomas.setMetric('cachingTooShort'); // @desc number of responses with too short (less than a week) caching time
-    phantomas.setMetric('cachingDisabled'); // @desc number of responses with caching disabled (max-age=0)
-
-    phantomas.setMetric('oldCachingHeaders');
-
-    phantomas.on('recv', function(entry, res) {
-        var ttl = getCachingTime(entry.url, entry.headers);
-
-        // static assets
-        if (entry.isImage || entry.isJS || entry.isCSS) {
-            if (ttl === false) {
-                phantomas.incrMetric('cachingNotSpecified');
-                phantomas.addOffender('cachingNotSpecified', entry.url);
-            } else if (ttl <= 0) {
-                phantomas.incrMetric('cachingDisabled');
-                phantomas.addOffender('cachingDisabled', entry.url);
-            } else if (ttl < 7 * 86400) {
-                phantomas.incrMetric('cachingTooShort');
-                phantomas.addOffender('cachingTooShort', entry.url + ' cached for ' + ttl + ' s');
-            }
-        }
-    });
-};

+ 3 - 3
lib/tools/phantomas/custom_modules/modules/jQYLT/jQYLT.js

@@ -17,7 +17,7 @@ exports.module = function(phantomas) {
     phantomas.setMetric('jQueryOnDOMReadyFunctions'); // @desc number of functions bound to onDOMReady event
     phantomas.setMetric('jQueryWindowOnLoadFunctions'); // @desc number of functions bound to windowOnLoad event
     phantomas.setMetric('jQuerySizzleCalls'); // @desc number of calls to Sizzle (including those that will be resolved using querySelectorAll)
-    //phantomas.setMetric('jQueryEventTriggers'); // @desc number of jQuery event triggers
+    phantomas.setMetric('jQueryEventTriggers'); // @desc number of jQuery event triggers
 
     var jQueryFunctions = [
         // DOM manipulations
@@ -245,7 +245,7 @@ exports.module = function(phantomas) {
                     });
 
 
-                    /*if (!jQuery.event) {
+                    if (!jQuery.event) {
                         phantomas.spy(jQuery.event, 'trigger', function(ev, data, elem) {
                             var path = phantomas.getDOMPath(elem),
                                 type = ev.type || ev;
@@ -255,7 +255,7 @@ exports.module = function(phantomas) {
                             phantomas.incrMetric('jQueryEventTriggers');
                             phantomas.addOffender('jQueryEventTriggers', '"%s" on "%s"', type, path);
                         });
-                    }*/
+                    }
 
                     // jQuery events bound to window' onLoad event (#451)
                     phantomas.spy(jQuery.fn, 'on', function(eventName, func) {

+ 25 - 13
lib/tools/phantomas/custom_modules/modules/javaScriptBottleYLT/javaScriptBottleYLT.js

@@ -4,44 +4,56 @@
  * @see http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/
  * @see http://www.quirksmode.org/blog/archives/2005/06/three_javascrip_1.html
  * @see http://www.stevesouders.com/blog/2012/04/10/dont-docwrite-scripts/
+ *
+ * Run phantomas with --spy-eval to count eval() calls (see issue #467)
  */
 /* global document: true, window: true */
 
-exports.version = '0.1.a';
+exports.version = '0.2';
 
 exports.module = function(phantomas) {
     'use strict';
+    
+    phantomas.setMetric('documentWriteCalls'); //@desc number of calls to either document.write or document.writeln @offenders
+    phantomas.setMetric('evalCalls'); // @desc number of calls to eval (either direct or via setTimeout / setInterval) @offenders
 
-    phantomas.setMetric('documentWriteCalls'); //@desc number of calls to either document.write or document.writeln
-    phantomas.setMetric('evalCalls'); // @desc number of calls to eval (either direct or via setTimeout / setInterval)
+    // spy calls to eval only when requested (issue #467)
+    var spyEval = phantomas.getParam('spy-eval') === true;
+    if (!spyEval) {
+        phantomas.log('javaScriptBottlenecks: to spy calls to eval() run phantomas with --spy-eval option');
+    }
 
     phantomas.once('init', function() {
-        phantomas.evaluate(function() {
+        phantomas.evaluate(function(spyEval) {
             (function(phantomas) {
                 function report(msg, caller, backtrace, metric) {
                     phantomas.log(msg + ': from ' + caller + '!');
                     phantomas.log('Backtrace: ' + backtrace);
+
                     phantomas.incrMetric(metric);
+                    phantomas.addOffender(metric, "%s from %s", msg, caller);
                 }
 
                 // spy calls to eval()
-                /*phantomas.spy(window, 'eval', function(code) {
-                    report('eval() called directly', phantomas.getCaller(), phantomas.getBacktrace(), 'evalCalls');
-                    phantomas.log('eval\'ed code: ' + (code || '').substring(0, 150) + '(...)');
-                });*/
+                if (spyEval) {
+                    phantomas.spy(window, 'eval', function(code) {
+                        report('eval() called directly', phantomas.getCaller(), phantomas.getBacktrace(), 'evalCalls');
+                        phantomas.log('eval\'ed code: ' + (code || '').substring(0, 150) + '(...)');
+                    });
+                }
 
                 // spy calls to setTimeout / setInterval with string passed instead of a function
-                /*phantomas.spy(window, 'setTimeout', function(fn, interval) {
+                phantomas.spy(window, 'setTimeout', function(fn, interval) {
                     if (typeof fn !== 'string') return;
 
                     report('eval() called via setTimeout("' + fn + '")', phantomas.getCaller(), phantomas.getBacktrace(), 'evalCalls');
-                });*/
+                });
 
-                /*phantomas.spy(window, 'setInterval', function(fn, interval) {
+                phantomas.spy(window, 'setInterval', function(fn, interval) {
                     if (typeof fn !== 'string') return;
 
                     report('eval() called via setInterval("' + fn + '")', phantomas.getCaller(), phantomas.getBacktrace(), 'evalCalls');
-                });*/
+                });
 
                 // spy document.write(ln)
                 phantomas.spy(document, 'write', function(arg) {
@@ -52,6 +64,6 @@ exports.module = function(phantomas) {
                     report('document.writeln() used', phantomas.getCaller(), phantomas.getBacktrace(), 'documentWriteCalls');
                 });
             })(window.__phantomas);
-        });
+        }, spyEval);
     });
 };

+ 0 - 2
lib/tools/phantomas/phantomasWrapper.js

@@ -29,14 +29,12 @@ var PhantomasWrapper = function() {
             'js-deep-analysis': task.options.jsDeepAnalysis || false,
             'user-agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36',
             'screenshot': task.options.screenshot || false,
-            'viewport': '1366x768',
 
             // Mandatory
             'reporter': 'json:pretty',
             'analyze-css': true,
             'skip-modules': [
                 'blockDomains', // not needed
-                'caching', // overriden
                 'domMutations', // not compatible with webkit
                 'domQueries', // overriden
                 'eventListeners', // overridden

+ 1 - 1
package.json

@@ -19,7 +19,7 @@
     "express": "~4.10.6",
     "lwip": "0.0.6",
     "meow": "^3.0.0",
-    "phantomas": "1.9.0",
+    "phantomas": "1.10.0",
     "ps-node": "0.0.3",
     "q": "~1.1.2",
     "rimraf": "~2.2.8",

+ 2 - 2
test/core/indexTest.js

@@ -54,7 +54,7 @@ describe('index.js', function() {
                 data.toolsResults.phantomas.should.have.a.property('offenders').that.is.an('object');
                 data.toolsResults.phantomas.offenders.should.have.a.property('DOMelementMaxDepth');
                 data.toolsResults.phantomas.offenders.DOMelementMaxDepth.should.have.length(1);
-                data.toolsResults.phantomas.offenders.DOMelementMaxDepth[0].should.equal('body > h1[1]');
+                data.toolsResults.phantomas.offenders.DOMelementMaxDepth[0].should.equal('body > h1[0]');
 
                 // Test rules
                 data.should.have.a.property('rules').that.is.an('object');
@@ -79,7 +79,7 @@ describe('index.js', function() {
                         "count": 1,
                         "tree": {
                             "body": {
-                                "h1[1]": 1
+                                "h1[0]": 1
                             }
                         }
                     }