Javascript packing problem - javascript

I have a minified/packed javascript file which is causing problems. The issue is that the non-packed input file has some missing semicolons somewhere which aren't a problem when there's line breaks, but when the file is packed, the line breaks are removed and that causes a parser error. For example:
//input
var x = function() {
doSomething();
} // note: no semicolon
var y = 'y';
//----
// output
var x=function(){doSomething();}var y='y';
// error here: ^
The strange thing is that when I do a replace on the output file to replace all semicolons with a semicolon and a new line, the file works! This is making it ludicrously hard to find the error, since AFAIK, I can't think of any situation where a line break after a semicolon should change anything. Any ideas about why doing this replace would make it work?

Uh... Have you tried JSLint?

When there's a line break, there's an implied semi-colon.

Use jslint to check your code. If you do this and get it passing with regards to semicolons, it should pack correctly.
In JavaScript, semicolons are implicitly added at newlines. This introduces situations that can be ambiguous. This blog post: http://robertnyman.com/2008/10/16/beware-of-javascript-semicolon-insertion/ describes the problem succinctly and gives an example.

JSlint is a good solution. Also, some code editors will find these kinds of errors for you. If I recall correctly, NetBeans catches these in realtime, as you type. I believe Komodo and Aptana do as well.

Related

What does --> do in JavaScript?

I have been unable to find any reference to this statement in any book, manual, or site. As far as I can tell, it functions exactly as a // comment. For example:
console.log("1");
--> console.log("2");
console.log("3");
will print
1
3
What I'm curious about is exactly what the difference between --> and // is, if any exists, and also why --> seems to completely absent from all the JavaScript references I've seen - the only reason I found out about it at all was because I accidentally typed it into Adobe Dreamweaver, and it was highlighted as a comment. Thanks!
Edit: Here is a functional jsFiddle demonstrating the behavior.
Edit 2: I've tested further, and I've discovered a few things.
This only works if there are exactly two dashes. -> and ---> will throw errors.
This only works with a "greater than" symbol. --< will throw an error.
This will not work in the middle of or at the end of a line. console.log("1"); --> console.log("2"); will throw an error.
My guess is that the JavaScript engine, forgiving as always, is silently ignoring the line because it looks like the end of an HTML comment (<!-- -->). JavaScript inlined in HTML has historically been wrapped in an HTML comment so that browsers that don't support JavaScript would not try to parse it.
Edit:
I've done some research, and this is indeed the case.
From V8's scanner.cc:
If there is an HTML comment end '-->' at the beginning of a
line (with only whitespace in front of it), we treat the rest
of the line as a comment. This is in line with the way
SpiderMonkey handles it.
From Rhino's Comment.java:
JavaScript effectively has five comment types:
// line comments
/* block comments */
/** jsdoc comments */
<!-- html-open line comments
^\s*--> html-close line comments
The first three should be familiar to Java programmers. JsDoc comments
are really just block comments with some conventions about the formatting
within the comment delimiters. Line and block comments are described in the
Ecma-262 specification.
Note that the --> comment is not part of the Ecma-262 specification.
This is not a comment. If you see it as a comment inside of code, then its probably showing as some kind of hanging chad HTML comment instead of the normal "//".
What's happening in this case is you are comparing using the greater than and then subtracting 1. Here are some examples...
var x = 3; var y = 3; console.log(x --> y);
false and x is now 2
If you place the normal comment characters "//", you'll get a syntax error (which you should)
The reason this is working as a comment is because it is returning as undefined. This is not safe to use as a comment. Oddly enough, it works fine in Chrome and you can throw all kinds of characters at it if you start the line with "-->".
--> something for nothing ~!####%$#%^$&%^&*()_+_=-=[]\];'\||?>;';;; alert('test'),,143187132458
However, within IE 11, it is always a syntax error. Very cool find

Simple way to check/validate javascript syntax

I have some big set of different javascript-snippets (several thousands), and some of them have some stupid errors in syntax (like unmatching braces/quotes, HTML inside javascript, typos in variable names).
I need a simple way to check JS syntax. I've tried JSLint but it send too many warnings about style, way of variable definitions, etc. (even if i turn off all flags). I don't need to find out style problems, or improve javascript quality, i just need to find obvious syntax errors. Of course i can simply check it in browser/browser console, but i need to do it automatically as the number of that snippets is big.
Add:
JSLint/JSHint reports a lot of problems in the lines that are not 'beauty' but working (i.e. have some potential problems), and can't see the real problems, where the normal compiler will simply report syntax error and stop execution. For example, try to JSLint that code, which has syntax errors on line 4 (unmatched quotes), line 6 (comma required), and line 9 (unexpected <script>).
document.write('something');
a = 0;
if (window.location == 'http://google.com') a = 1;
document.write("aaa='andh"+a+"eded"');
a = {
something: ['a']
something2: ['a']
};
<script>
a = 1;
You could try JSHint, which is less verbose.
Just in case anyone is still looking you could try Esprima,
It only checks syntax, nothing else.
I've found that SpiderMonkey has ability to compile script without executing it, and if compilation failed - it prints error.
So i just created small wrapper for SpiderMonkey
sub checkjs {
my $js = shift;
my ( $js_fh, $js_tmpfile ) = File::Temp::tempfile( 'XXXXXXXXXXXX', EXLOCK => 0, UNLINK => 1, TMPDIR => 1 );
$| = 1;
print $js_fh $js;
close $js_fh;
return qx(js -C -f $js_tmpfile 2>&1);
}
And javascriptlint.com also deals very good in my case. (Thanks to #rajeshkakawat).
Lots of options if you have an exhaustive list of the JSLint errors you do want to capture.
JSLint's code is actually quite good and fairly easy to understand (I'm assuming you already know JavaScript fairly well from your question). You could hack it to only check what you want and to continue no matter how many errors it finds.
You could also write something quickly in Node.js to use JSLint as-is to check every file/snippet quickly and output only those errors you care about.
Just use node --check filename
Semantic Designs' (my company) JavaScript formatter read JS files and formats them. You don't want the formatting part.
To read the files it will format, it uses a full JavaScript parser, which does a complete syntax check (even inside regular expressions). If you run it and simply ignore the formatted result, you get a syntax checker.
You can give it big list of files and it will format all of them. You could use this to batch-check your large set. (If there are any syntax errors, it returns a nonzero error status to a shell).

Why does jshint complain about linebreak within expression?

When passing the following code to jshint, it considers the linebreak in the if-condition to be bad, saying "Bad line breaking before '&&'."
if (1 == 1
&& true) {
console.log("hello world");
}
However, having the linebreak after '&&' is fine.
if (1 == 1 &&
true) {
console.log("hello world");
}
Why does jshint consider the first to be wrong and the latter to be right?
According to a discussion on GitHub:
This may cause problems like semi colon insertion and old javascript parsers breaking. Please check a large range of browsers.
This check can be disabled with laxbreak:true.
The laxbreak option is on its way to deprecation, but I'm not sure if the default jshint behavior will change.
The creator of JSHint probably doesn't like this kind of wrapping and prefers the && in the first line which seems to be much more common:
The primary reasoning behind this convention is that the operator makes it clear that the line is a continuation of the preceding line. With the operator before the line break, this is much harder to spot.
Actually there's an issue about exactly what you are asking about on Github: https://github.com/jshint/jshint/issues/557

Razor/JavaScript and trailing semicolon

Using Visual Studio 2012, on a Razor view page, in the JavaScript section, I am getting what I think is a battle between Razor syntax vs JavaScript syntax. In particular, the trailing semicolon in the script section is flagged by intellisense and a compiler warning (not error) is delivered:
'Warning 13 Syntax error'.
If I remove it, then I get a statement termination recommendation (ReSharper in this case, but just good practice).
<script type="text/javascript">
$().ready(function(){
var customer = #Html.Raw(ViewBag.CustomerJSON); // <- Razor (I think) doesn't like this semicolon
});
</script>
Is this a bug in Razor? If so, is there a way I can rewrite this to avoid this issue?
Is this a bug in Razor?
Absolutely not. Run your application, and it will work as expected.
It is a bug in the tools you are using (Visual Studio 2012, ReSharper, ...) that are incapable of recognizing perfectly valid syntax and warning you about something that you shouldn't be warned about. You could try opening an issue on the Microsoft Connect site and signalling this bug if that hasn't already been done.
Since this still seems to be happening and it is a nuisance I figured I will at least let others know what I ended up using as a "hack". I don't want to ignore the warning and would rather accept a hokier syntax (and yes someone is going to say this will kill performance :))
What I use as a workaround is to use a client side addition at the end. For me this error occurred on defining an "integer" constant, so
window.foo = #(Model.Something);
gave me the good old semicolon error. I simply changed this to:
window.foo = #Model.Something + 0;
(In the stated questions case you should just be able to add '', so + ''.
I know there is a whole another addition happening on the client and it isn't elegant, but it does avoid the error. So use it or don't, but I prefer this over seeing the warning/error.
If someone knows of a server-side syntactical workaround for this I would prefer this to the client-side one, so please add.
I found that wrapping the Razor syntax in a JavaScript identity function also makes the IDE happy.
<script type="text/javascript">
#* I stands for Identity *#
function I(obj) { return obj; }
$().ready(function(){
var customer = I(#Html.Raw(ViewBag.CustomerJSON));
});
</script>
This worked for me:
var customer = #Html.Raw(ViewBag.CustomerJSON + ";")
Here's a workaround for booleans:
var myBool = #(Model.MyBool ? "true;" : "false;")
This worked for me
#Html.Raw(string.Format("var customer = {0};", ViewBag.CustomerJSON));
<script type="text/javascript">
$().ready(function(){
var customerName = ('#ViewBag.CustomerName'); // <- wrap in parens
});
</script>
Isn't it as simple as wrapping in parentheses? Putting values through the console seem to work fine with no side effect.
It works for strings, but it still gives the error for non-quoted values, but I still like this for string values. For numbers you could just use parseInt('#Model.TotalResultCount', 10).

Why no semicolon at the end of js expression in javascriptmvc app?

I am starting to learn javascriptmvc, and in code samples, I see code without semicolons at the end of expressions. Does this count on automatic semicolon insertion or am I missing something? Code example below:
$.Controller("Contacts.Controller", {
init: function(){
this.params = new Mxui.Data();
$("#category .list_wrapper").mxui_data_list({
model : Contacts.Models.Category,
show : "//contacts/views/categoryList",
create: "//contacts/views/categoryCreate"
}) // <------ NO SEMICOLON
$("#location .list_wrapper").mxui_data_list({
model : Contacts.Models.Location,
show : "//contacts/views/categoryList",
create: "//contacts/views/categoryCreate"
}) // <------ NO SEMICOLON
$("#company .list_wrapper").mxui_data_list({
model : Contacts.Models.Company,
show : "//contacts/views/companyList",
create: "//contacts/views/companyCreate"
}) // <------ NO SEMICOLON
// etc...
}
}) // <------ NO SEMICOLON
Javascript can be forgiving about the lack of a semicolon in ways that other languages are not. However a semicolon is recommended where you've pointed them out.
If you run the code you've given through JSLint, it throws up a whole stack of warnings, including complaining about those missing semicolons.
JSLint is a tool for telling you about things in your code which may not be syntax errors but which could cause problems. It generally throws up a lot of errors, even for relatively well written code, but it is good for picking up things which you should fix.
I would say that those code samples are poorly written because of the missing semi-colons.
Semicolons are only mandatory in inline event handlers.
MOST anywhere else, a linefeed is enough. Here is an example of where it is not enough:
Why is a semicolon required at end of line?
And as pointed out, do not leave out semicolons if you want to minify your scripts.
A lot of semicolons are optional in javascript, though recommended to avoid confusion
https://mislav.net/2010/05/semicolons/

Categories

Resources