Merge "resourceloader: Restore mw.loader.store update postponing logic"
[lhc/web/wiklou.git] / resources / src / mediawiki.inspect.js
index e2030c9..f4545de 100644 (file)
        function sortByProperty( array, prop, descending ) {
                var order = descending ? -1 : 1;
                return array.sort( function ( a, b ) {
+                       if ( a[ prop ] === undefined || b[ prop ] === undefined ) {
+                               // Sort undefined to the end, regardless of direction
+                               return a[ prop ] !== undefined ? -1 : b[ prop ] !== undefined ? 1 : 0;
+                       }
                        return a[ prop ] > b[ prop ] ? order : a[ prop ] < b[ prop ] ? -order : 0;
                } );
        }
         */
        inspect.dumpTable = function ( data ) {
                try {
-                       // Bartosz made me put this here.
-                       if ( window.opera ) { throw window.opera; }
                        // Use Function.prototype#call to force an exception on Firefox,
                        // which doesn't define console#table but doesn't complain if you
                        // try to invoke it.
                } catch ( e ) {}
                try {
                        console.log( JSON.stringify( data, null, 2 ) );
-                       return;
                } catch ( e ) {}
-               mw.log( data );
        };
 
        /**
         *
         * When invoked without arguments, prints all available reports.
         *
-        * @param {...string} [reports] One or more of "size", "css", or "store".
+        * @param {...string} [reports] One or more of "size", "css", "store", or "time".
         */
        inspect.runReports = function () {
                var reports = arguments.length > 0 ?
                        Object.keys( inspect.reports );
 
                reports.forEach( function ( name ) {
+                       if ( console.group ) {
+                               console.group( 'mw.inspect ' + name + ' report' );
+                       } else {
+                               console.log( 'mw.inspect ' + name + ' report' );
+                       }
                        inspect.dumpTable( inspect.reports[ name ]() );
+                       if ( console.group ) {
+                               console.groupEnd( 'mw.inspect ' + name + ' report' );
+                       }
                } );
        };
 
                        var module = mw.loader.moduleRegistry[ moduleName ];
 
                        // Grep module's JavaScript
-                       if ( $.isFunction( module.script ) && pattern.test( module.script.toString() ) ) {
+                       if ( typeof module.script === 'function' && pattern.test( module.script.toString() ) ) {
                                return true;
                        }
 
        };
 
        /**
+        * @private
         * @class mw.inspect.reports
         * @singleton
         */
                                } catch ( e ) {}
                        }
                        return [ stats ];
+               },
+
+               /**
+                * Generate a breakdown of all loaded modules and their time
+                * spent during initialisation (measured in milliseconds).
+                *
+                * This timing data is collected by mw.loader.profiler.
+                *
+                * @return {Object[]} Table rows
+                */
+               time: function () {
+                       var modules;
+
+                       if ( !mw.loader.profiler ) {
+                               mw.log.warn( 'mw.inspect: The time report requires $wgResourceLoaderEnableJSProfiler.' );
+                               return [];
+                       }
+
+                       modules = inspect.getLoadedModules()
+                               .map( function ( moduleName ) {
+                                       return mw.loader.profiler.getProfile( moduleName );
+                               } )
+                               .filter( function ( perf ) {
+                                       // Exclude modules that reached "ready" state without involvement from mw.loader.
+                                       // This is primarily styles-only as loaded via <link rel="stylesheet">.
+                                       return perf !== null;
+                               } );
+
+                       // Sort by total time spent, highest first.
+                       sortByProperty( modules, 'total', true );
+
+                       // Add human-readable strings
+                       modules.forEach( function ( module ) {
+                               module.totalInMs = module.total;
+                               module.total = module.totalInMs.toLocaleString() + ' ms';
+                       } );
+
+                       return modules;
                }
        };