How to display all JavaScript global variables with static code analysis? - javascript

I know that I can type into Chrome or FF the following command:
Object.keys(window);
but this displays DHTMLX stuff and also function names in which I'm not interested in. And it doesn't display variables in functions that have not been executed yet. We have more than 20,000 lines of JavaScript codebase, so I would prefer static code analyis. I found JavsScript Lint. It is a great tool but I don't know how to use it for displaying global vars.
So I'm searching for memory leaks, forgotten var keywords, and so on...

To do [only] what you're asking, I think you're looking for this:
for each (obj in window) {
if (window.hasOwnProperty(obj)) {
console.log(obj);
}
}
I haven't linted that code, which is unlike me, but you get the idea. Try setting something first (var spam = "spam";) and you'll see it reported on your console, and not the cruft you asked about avoiding.
That said, JLRishe is right; JSLint executes JavaScript in your browser without "phoning home", so feel free to run it. There are also many offline tools for JSLinting your code. I use a plugin for Sublime Text, for instance.
If you'd like some simplest-case html/JavaScript code to "wrap" JSLint, I've got an example here. Just download the latest jslint.js file from Crockford's repository into the same directory, and poof, you're linting with a local copy of JSLint.js. Edit: Added code in a new answer here.
Though understand that you're linting locally with that wrapper or when you visit JSLint.com. Honestly, I can say with some confidence, Crockford would rather not see our code. ;^) You download JSLint.js (actually webjslint, a minified compilation of a few files) from JSLint.com, but you execute in the browser.
(Admittedly, you're technically right -- you never know when that site could be compromised, and to be completely on the up and up, you sh/c/ould vet jslint.js each time you grab a fresh copy. It is safer to run locally, but as of this writing, you appear safe to use JSLint.com. Just eyeball your favorite browser's Net tab while running some test, non-proprietary code, and see if any phoning happens. Or unplug your box's network cable!)
Rick's answer to use "use strict"; is another great suggestion.

A great way to catch undeclared variables is to add 'use strict' to your code.
The errors will appear in the console, or you could display them in a try ... catch block:
'use strict';
try {
var i= 15;
u= 25;
} catch(ee) {
alert(ee.message);
}

I found a very good solution to list all the global variables with the jsl command line tool:
Here is the documentation
I just have to put /*jsl:option explicit*/ into each file that I want to check. Then it is enough to run ./jsl -process <someFile> | grep 'undeclared identifier'
It is also possible to use referenceFile that contains some intentional global variables /*jsl:import <referenceFile>*/ so these variables will not be listed.

Related

Strange Javascript validation in dreamweaver CC

I've installed Dreamweaver CC 2015 and found out that I have MYRIAD errors in my working JavaScript files.
Also I have MYRIAD errors in imported JavaScript libraries, including jQuery.
The most important "error" is this one in the beginning of every working function:
Missing "use strict" statement.
It worked quite well without "use strict" and I've never even seen this statement anywhere.
Another strange one is:
Extending prototype of native object: 'Array'.
Here is the code which provokes the warning:
Array.prototype.sortOn = function(key){
this.sort(function(a, b){
if(a[key] < b[key]){
return -1;
}else if(a[key] > b[key]){
return 1;
}
return 0;
});
};
So my options are:
Ditch Dreamweaver and use another IDE (the worst, because it works perfectly fine for my purposes - I'm sole HTML/CSS/JS/PHP/MySQL developer in my project.
Fix all errors like Dreamweaver wants, because it has a good point. Then please explain why? I'm OK with changing "==" to "===", adding "var" before variable declarations, not using "return" after "if" without curly braces, but that "use strict" thing bothers me.
Tweak the JavaScript validation, so only critical errors are shown - the best option for me - but I don't know HOW to do it?
What's the best option to go with?
Any help greatly appreciated.
Here's what I figured out.
The problem was that I was not aware of JSHint and JSLint solutions for validating javascript. JSHint is integrated into Dreamweaver CC and is easily configurable, provided you know what to do.
Normally JSHint has three ways to tweak it, but they don't work in the Dreamweaver environment.
What you should do is:
From the top menu select Edit -> Preferences (Dreamweaver -> Preferences on Mac)
Choose "Linting" from the side menu.
Select "JS" and click "Edit and save changes".
The file JS.jshintrc will be opened in Dreamweaver.
Edit the file like you normally would (see JSHint options) and save.
In my specific case I changed this:
"strict":false,
"undef":false,
"unused":false
...which means that I don't have to put "use strict" everywhere and may leave definitions and usage of variables in different files. YES, I don't use wrapper functions and use lots of globals. YES, I know it's bad, but refactoring this is not the highest priority in my schedule.
Of course I will change all three those options to "true" and refactor all my JS files to comply to standards when the time comes.
Turning off the "undef" check is a sledge hammer, as JSHint will then ignore all variable and function name typos. You won't find the typo until run time, which is annoying and time wasting.
Rather than disabling the "undef" messages completely, I've been using JSHint Inline Directives near the top of my .js files. For example:
/* globals myGlobalVar, myGlobalFunction */
var myLocalVar = myGlobalVar;
myGlobalFunction();
With the globals directive in the file, JSHint will not mark myGlobalVar or myGlobalFunction() as undefined errors. Using "globals" inline directives has the added benefit of documenting the dependencies between your .js files.
Read about JSHint inline directives here:
http://jshint.com/docs/#inline-configuration

how do you allow javascript communications with Flex/Flash/Actionscript

Well here's a problem.
I've got a website with large javascript backend. This backend talks to a server over a socket with a socket bridge using http://blog.deconcept.com/swfobject/
The socket "bridge" is a Flex/Flash .swf application/executable/plugin/thing for which the source is missing.
I've got to change it.
More facts:
file appExePluginThing.swf
appExePluginThing.swf Macromedia Flash data (compressed), version 9
I've used https://www.free-decompiler.com/flash/ to decompile the .swf file and I think I've sorted out what's the original code vs the libraries and things Flash/Flex built into it.
I've used FDT (the free version) to rebuild the decompiled code into MYappExePluginThing.swf so I can run it with the javascript code and see what happens.
I'm here because what happens isn't good. Basically, my javascript code (MYjavascript.js) gets to the point where it does
window.log("init()");
var so = new SWFObject("flash/MYappExePluginThing.swf"", socketObjectId, "0", "0", "9", "#FFFFFF");
window.log("init() created MYappExecPluginThing!!!");
so.addParam("allowScriptAccess", "always");
log("init() added Param!!");
so.write(elId);
log("init() wrote!");
IE9's console (yeah, you read that right) shows
init()
created MYappExecPluginThing!!!
init() added Param!!
init() wrote!
but none of the debugging i've got in MYappExePluginThing.as displays and nothing else happens.
I'm trying to figure out what I've screwed up/what's going on? Is MYappExePluginThing.as running? Is it waiting on something? Did it fail? Why aren't the log messages in MYappExePluginThing.as showing up?
The first most obvious thing is I'm using FDT which, I suspect, was not used to build the original. Is there some kind of magic "build javascript accessible swf thing" in FlashBuilder or some other IDE?
First noteworthy thing I find is:
file MYappExePluginThing.swf
MYappExePluginThing.swf Macromedia Flash data (compressed), version 14
I'm using Flex 4.6 which, for all I know, may have a completely different mechanism for allowing javascript communication than was used in appExePluginThing.swf
Does anyone know if that's true?
For example, when FDT runs this thing (I can compile but FDT does not create a .swf unless i run it) I get a warning in the following method:
private function init() : void
{
Log.log("console.log", "MYappExePluginThing init()");
//var initCallback:String = Application.application.parameters.initCallback?Application.application.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
var initCallback:String = FlexGlobals.topLevelApplication.parameters.initCallback?FlexGlobals.topLevelApplication.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
try
{
ExternalInterface.addCallback("method1Callback",method1);
ExternalInterface.addCallback("method2Callback",method2);
ExternalInterface.call(initCallback);
}
catch(err:Error)
{
Log.log("console.log", "MYappExePluginThing init() ERROR err="+err);
}
}
I got a warning that Application.application was deprecated and I should change:
var initCallback:String = Application.application.parameters.initCallback?Application.application.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
to:
var initCallback:String = FlexGlobals.topLevelApplication.parameters.initCallback?FlexGlobals.topLevelApplication.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
which I did but which had no effect on making the thing work.
(FYI Log.log() is something I added:
public class Log{
public static function log(dest:String, mssg:String):void{
if(ExternalInterface.available){
try{
ExternalInterface.call(dest, mssg);
}
catch(se:SecurityError){
}
catch(e:Error){
}
}
trace(mssg);
}
}
)
Additionally, in MYjavascript.js MYappExePluginThing_init looks like this:
this.MYappExePluginThing_init = function () {
log("MYjavascript.js - MYappExePluginThing_init:");
};
Its supposed to be executed when MYappExePluginThing finishes initializing itself.
Except its not. The message is NOT displaying on the console.
Unfortunately, I cannot find any references explaining how you allow javascript communication in Flex 4.6 so I can check if I've got this structured correctly.
Is it a built in kind of thing all Flex/Flash apps can do? Is my swf getting accessed? Is it having some kind of error? Is it unable to communicate back to my javascript?
Does anyone have any links to references?
If this was YOUR problem, what would you do next?
(Not a full solution but I ran out of room in the comment section.)
To answer your basic question, there's nothing special you should need to do to allow AS3-to-JS communication beyond what you've shown. However, you may have sandbox security issues on localhost; to avoid problems, set your SWFs as local-trusted (right-click Flash Player > Global Settings > Advanced > Trusted Location Settings). I'm guessing this not your problem, though, because you'd normally get a sandbox violation error.
More likely IMO is that something is broken due to decompilation and recompilation. SWFs aren't meant to do that, it's basically a hack made mostly possible due to SWF being an open format.
What I suggest is that you debug your running SWF. Using break-points and stepping through the code you should be able to narrow down where things are going wrong. You can also more easily see any errors your SWF is throwing.
Not really an answer, but an idea to get you started is to start logging everything on the Flash side to see where the breakage is.
Since you're using IE, I recommend getting the Debug flash player, installing it, then running Vizzy along side to show your traces.
Should give you a good idea of where the app is breaking down.
Vizzy
Debug Player

Best practice for removing console.log and other debug code from your release JavaScript?

I've seen some of the console wrappers that stop errors in browser with a console and more advanced ones that enable logging in older browsers. But none that I've seen help switch on and off the debug code.
At the moment I do a find and replace to comment out debug code. There must be a better way?
I'm using Combres which uses YUI to minify the JavaScript. I've seen some posts that mention using double semi colons to mark lines to be removed in the minification process. Is this a hack or good practice?
Probably you should have your own wrapper around console.log() and log your debug info via that wrapper. That way you can replace that single function with an empty function once you deploy to production so the console won't flood with debugging info. You can also replace the actual console.log function with an empty function, but that would prevent any Javascript from outputting to console, not just yours.
If you look at how the YUI Framework does it, they actually use a regex and generate 3 files from source. One that has the logging -debug, one that has the logging stripped out, just the file name, and a minified version with no logging. Then you can set a global config to say which version you want. I've worked that way in the past and works nicely.
Define your own debugging function that'd be wrapper around console.log or anything else you want and make sure that minifier can easily deduce that it is no-op if you make it empty. After that, once you comment function body out, most minifiers should detect that there's nothing to call or inline and remove references to your function completely.
Here's the example:
(function() {
function debug() {
console.log(arguments)
}
function main() {
debug(123)
alert("This is production code!")
debug(456)
}
main()
})()
I've put it into anonymous function to restrict scope of debug and don't let it be assigned to window - that allows minifier to easily decide if it is necessary or not. When I paste this code to online GCC, I get:
(function(){function a(){console.log(arguments)}a(123);alert("This is production code!");a(456)})();
But once I add // before console.log to make debug empty, GCC compiles it to:
(function(){alert("This is production code!")})();
...removing all traces of debug code completely!
Use Y.log() instead, and then you can use gallery-log-filter to filter the log messages that you want to see printed.

find dead JavaScript code?

We are refactoring a legacy web app and as a result are "killing" quite a lot of JavaScript code but we're afraid of deleting what we think is dead code due to not being sure. Is there any tool / technique for positively identifying dead code in JavaScript?
Without looking for anything too complex:
JSLint (not really a static analyzer, but if you give it your concatenated development code, you'll see what methods are never called, at least in obvious scoping contexts)
Google Closure Compiler
Google Closure Linter
You can use deadfile library:
https://m-izadmehr.github.io/deadfile/
It can simply find unused files, in any JS project.
Without any config, it supports ES6, JSX, and Vue files:
There's grep. Use it to find function calls. Suppose you have a method called dostuff(). Use grep -r "dostuff()" * --color on your project's root directory. Unless you find anything other than the definition, you can safely erase it.
ack is also a notable alternative to grep.
WebStorm IDE from JetBrains can highlight deadcode and unused variables in your project.
You could use code optimizers as Google Closure Compiler, however it's often used for minimizing code.
function hello(name) {
alert('Hello, ' + name);
}
function test(){
alert('hi');
}
hello('New user');
Will result in
alert("Hello, New user");
For example.
Another thing you could do is to use Chrome's Developer Tools (or Firebug) to see all function calls. Under Profiles you can see which functions are being called over time and which are not.
Chrome has come up with new feature which lets developer see the code coverage, ie., which lines of codes were executed.
This certainly is not a one stop solution, but can extend a helping hand to developers to get code insights.
Check this link for details
Rolled as apart of Chrome 59 release
If you want to automate this I'd take a look at https://github.com/joelgriffith/navalia, which exposes an automated API to do just that:
const { Chrome } = require('navalia');
const chrome = new Chrome();
chrome.goto('http://joelgriffith.net/', { coverage: true })
.then(() => chrome.coverage('http://joelgriffith.net/main.bundle.js'))
.then((stats) => console.log(stats)) // Prints { total: 45913, unused: 5572,
percentUnused: 0.12135996340905626 }
.then(() => chrome.done());
More here: https://joelgriffith.github.io/navalia/Chrome/coverage/
I hate this problem, and that there are no good tools for solving it, despite the parse-heavy javascript ecosystem. As mentioned in another answer, deadfile is pretty neat, but I couldn't make it work for my codebase, which uses absolute imports from a src directory. The following bash was good enough to get an idea of whether any files weren't imported anywhere (I found some!), which was easily hand-verifiable.
for f in $(find src -name '*.js' | grep -E 'src/(app|modules|components).*\.js$' | grep -v '.test.js'); do
f=${f/src\//};
f=${f/\/index.js/};
f=${f/.js/};
echo "$f imported in"$(grep -rl "$f" src | wc -l)" files"
done
I didn't care about tests/resources, hence the app|modules|components bit. The string replacements could be cleaned up significantly too, but hopefully this will be useful to someone.

JavaScript: Possible uses for #debug directive?

Where I work, all our JavaScript is run through a compiler before it's deployed for production release. One of the things this JavaScript compiler does (beside do things like minify), is look for lines of code that appear like this, and strip them out of the release versions of our JavaScript:
//#debug
alert("this line of code will not make it into the release build")
//#/debug
I haven't look around much but I have yet to see this //#debug directive used in any of our JavaScript.
What is it's possible usefulness? I fail to see why this could ever be a good idea and think #debug directives (whether in a language like C# or JavaScript) are generally a sign of bad programming.
Was that just a waste of time adding the functionality for //#debug or what?
If you were using a big JavaScript library like YUI that has a logger in it, it could only log debug messages when in debug mode, for performance.
Since it is a proprietary solution, we can only guess the reasons. A lot of browsers provide a console object to log various types of messages such as debug, error, etc.
You could write a custom console object is always disabled in production mode. However, the log statements will still be present, but just in a disabled state.
By having the source go though a compiler such as yours, these statements can be stripped out which will reduce the byte size of the final output.
Think of it as being equivalent to something like this:
// in a header somewhere...
// debug is off by default unless turned on at compile time
#ifndef DEBUG
#define DEBUG 0
#endif
// in your code...
var response = getSomeData({foo:1, bar:2});
#if DEBUG
console.log(response);
#endif
doStuffWith(response);
This kind of thing is perfectly acceptable in compiled languages, so why not in (preprocessed) javascript?
I think it was useful (perhaps extremely useful) back a few years, and was probably the easiest way for a majority of developers to know what was going on in their JavaScript. That was because IDE's and other tools either weren't mature enough or as widespread in their use.
I work primarily in the Microsoft stack (so I am not as familiar with other environments), but with tools like VS2008/VS2010, Fiddler and IE8's (ugh! - years behind FF) dev tools and FF tools like firebug/hammerhead/yslow/etc., peppering alerts in your JavaScript isn't really necessary anymore for debugging. (There's probably a few instances where it's useful - but not nearly as much now.) Able to step through JavaScript, inspect requests/responses, and modify on the fly really makes debugging alert statements almost obsolete.
So, the //#debug was useful - probably not so much now.
I've used following self-made stuf:
// Uncomment to enable debug messages
// var debug = true;
function ShowDebugMessage(message) {
if (debug) {
alert(message);
}
}
So when you've declared variable debug which is set to true - all ShowDebugMessage() calls would call alert() as well. So just use it in a code and forget about in place conditions like ifdef or manual commenting of the debug output lines.
For custom projects without any specific overridden console.
I would recommend using: https://github.com/sunnykgupta/jsLogger , it is authored by me.
Features:
It safely overrides the console.log. Takes care if the console is not available (oh yes, you need to factor that too.)
Stores all logs (even if they are suppressed) for later retrieval.
Handles major console functions like log, warn, error, info.
Is open for modifications and will be updated whenever new suggestions come up.

Categories