5

Closed

Ajax Minifier breaks jQuery 1.7.1 in Opera

description

The site http://opendataforafrica.org/ throws a warning that Opera isn't supported--due to the fact that the Ajax Minifier produces non-ES5.1 spec compliant code that throws in current versions of Opera.
 
To reproduce, go to opendataforafrica.org and click past the browser warning sign. In the console (either Dragonfly or the Error Console), you'll see:
 
[June 9, 2026 10:15:36 PM] JavaScript - http://opendataforafrica.org/_cassette/scriptbundle/Js/jQuery_bae36a9c51cd203132478b8e6a47bc6684efcb77
Linked script compilation
Syntax error at line 24 while loading: expected ')', got keyword 'in'
or(i.isArray(t)||(t in e?t=[t]:(t=i.came
 
The offending line is here: if(e){for(i.isArray(t)||(t in e?t=[t]:(t=i.camelCase(t),t=t in e?[t]:t.split(" "))),s=0,c=t.length;s<c;s++)delete e[t[s]];if(!(r?st:i.isEmptyObject)(e))return}}
 
Minified from,
 
(from jQuery 1.7.1, https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js):
if ( thisCache ) {
 
// Support array or space separated string names for data keys
if ( !jQuery.isArray( name ) ) {
 
// try the string as a key before any manipulation
if ( name in thisCache ) {
name = [ name ];
} else {
 
// split the camel cased version by spaces unless a key with the spaces exists
name = jQuery.camelCase( name );
if ( name in thisCache ) {
name = [ name ];
} else {
name = name.split( " " );
}
}
}
 
for ( i = 0, l = name.length; i < l; i++ ) {
delete thisCache[ name[i] ];
}
 
// If there is no data left in the cache, we want to continue
// and let the cache object itself get destroyed
if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
return;
}
}
 
12.6 of ES5.1 says that the "NoIn" production should be used for the "head" of a for-loop, so the parser is just being spec compliant here & following the grammar. We added as part of ES5.1 work and getting test262 to pass. Unfortunately other browsers aren't spec compliant in this matter.
 
It would be nice if the Ajax Minifier could produce ES5.1 compliant output. :)
Closed Apr 12, 2013 at 4:07 PM by ronlo
I haven't checked in a while, but version 12.14 of Opera seems to have their bug fixed. I ran this code on an HTML page and it now works:
    for(var hasAlert=("alert" in window), ndx=0; ndx " + ndx + "");
    }
    document.write("has alert: " + hasAlert + "");
I don't know at what version they actually fixed their parsing bug, but it seems to be a done deal now.

comments

ronlo wrote Apr 12, 2012 at 4:24 PM

I believe you are mistaken here. I'll take a look at this again, but this is a known issue -- WITH OPERA. AjaxMin is producing ES5.1-compliant code; Opera incorrectly implements the spec. If you read the spec, the NoIn production only goes down to the RelationaExpressionNoIn level. Because the in-operator in this case is enclosed within parentheses, it is actually under the PrimaryExpression construct, which does not have a separate NoIn flavor. It is perfectly valid code, as all other browsers recognize. Opera is wrong here. Someone had reported this before, and I thought I put in a flag or some other fix for this; I'll check the source history.

miketaylr wrote Apr 12, 2012 at 4:31 PM

Hey ronlo,

Yeah, you're right--I was mistaken.

In this case, we're basically looking at:
for ((a in A); b; c);
which is a valid Statement per ES5. Provided the "in" is bracketed, it is valid, so the example I've given is bogus.

This does, however, still mean that things such as:
  • for (a && a in A; b; c);
    are wrong per spec (hence the confusion).
We've noted this as a CORE bug and hopefully will have it fixed soon.

ronlo wrote Apr 12, 2012 at 4:52 PM

Yes, your second example is invalid ES5 code -- AjaxMin shouldn't be producing code like that. I believe this was fixed in AjaxMin version 4.35, and in version 4.41 a kill switch was added (-kill:0x40000000000) the prevent ANY in-operators from being moved into a for-statement (see issue #16850).

miketaylr wrote Apr 13, 2012 at 4:38 PM

We've committed a fix for this in CORE just now--hopefully out in public builds soon!

abm wrote Jul 27, 2012 at 11:48 AM

Is this bug committed in the 4.59? Please confirm and change the status if it was committed in the public release.

ronlo wrote Aug 1, 2012 at 8:32 PM

Not sure I understand the question, abm. The "bug" here is in the Opera code-base, not AjaxMin: AjaxMin is producing valid JavaScript, but Opera is choking on it. There is a kill-switch that can be used in AjaxMin if you want to work around the Opera bug (see below), but I am not tracking Opera release that I believe miketaylr references, so I don't know the state of the fix to Opera. Maybe Mike can give an update on that?

miketaylr wrote Aug 1, 2012 at 9:17 PM

Yes, this has been fixed in Opera--but not in any public builds yet. It was fixed in core-integration-point 324, and Opera Next is currently at 310. So hopefully soon it will be in stable Opera.

chriskeeble wrote Oct 15, 2012 at 9:45 PM

Is there a CodeSettings (or other) option) to implement the workaround (kill switch) ?

chriskeeble wrote Oct 15, 2012 at 9:58 PM

For others needing to know how to implement the killswitch in an ASP.NET application:

Where 'file' is a String containing the file contents...

file = new Minifier().MinifyJavaScript(file, new CodeSettings { KillSwitch = 0x40000000000 });

ronlo wrote Oct 15, 2012 at 10:33 PM

Correct. And if you don't like magic numbers, you can also go:

file = new Minifier().MinifyJavaScript(file, new CodeSettings { KillSwitch = (long)TreeModifications.MoveInExpressionsIntoForStatement });

The TreeModifications enumeration is defined in CodeSettings.cs. There are a lot of them, and there should be descriptive Intellisense comments for each one.

chriskeeble wrote Oct 15, 2012 at 11:13 PM

Thanks ronlo - much nicer. Good to know!

ronlo wrote Apr 12, 2013 at 4:07 PM

I haven't checked in a while, but version 12.14 of Opera seems to have their bug fixed. I ran this code on an HTML page and it now works:
    for(var hasAlert=("alert" in window), ndx=0; ndx < 5; ++ndx)
    {
        document.write("<h1>" + ndx + "</h1>");
    }
    document.write("<h2>has alert: " + hasAlert + "</h2>");
I don't know at what version they actually fixed their parsing bug, but it seems to be a done deal now.