created by Kentaro SATO <kentaro@ranvis.com>
http://ken.ranvis.com/script/java/yuicompressor.html

diff -ru orig/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java com/yahoo/platform/yui/compressor/JavaScriptCompressor.java
--- orig/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java	2008-07-10 14:38:00.000000000 +0900
+++ com/yahoo/platform/yui/compressor/JavaScriptCompressor.java	2008-07-18 22:51:13.796875000 +0900
@@ -533,7 +533,7 @@
     }
 
     public void compress(Writer out, int linebreak, boolean munge, boolean verbose,
-            boolean preserveAllSemiColons, boolean disableOptimizations)
+            boolean preserveAllSemiColons, boolean endSemiColon, boolean disableOptimizations)
             throws IOException {
 
         this.munge = munge;
@@ -549,7 +549,7 @@
         buildSymbolTree();
         // DO NOT TOUCH this.tokens BETWEEN THESE TWO PHASES (BECAUSE OF this.indexedScopes)
         mungeSymboltree();
-        StringBuffer sb = printSymbolTree(linebreak, preserveAllSemiColons);
+        StringBuffer sb = printSymbolTree(linebreak, preserveAllSemiColons, endSemiColon);
 
         out.write(sb.toString());
     }
@@ -1070,7 +1070,7 @@
         globalScope.munge();
     }
 
-    private StringBuffer printSymbolTree(int linebreakpos, boolean preserveAllSemiColons)
+    private StringBuffer printSymbolTree(int linebreakpos, boolean preserveAllSemiColons, boolean endSemiColon)
             throws IOException {
 
         offset = 0;
@@ -1210,6 +1210,8 @@
                         if (token.getType() != Token.LP &&
                                 token.getType() != Token.LB &&
                                 token.getType() != Token.LC &&
+                                (token.getType() != Token.SEMI
+                                    || getToken(1).getType() != Token.RC) &&	// followed by ;}
                                 token.getType() != Token.STRING &&
                                 token.getType() != Token.REGEXP) {
                             result.append(' ');
@@ -1305,10 +1307,16 @@
         // several minified files (the absence of an ending semi-colon at the
         // end of one file may very likely cause a syntax error)
         if (!preserveAllSemiColons && result.length() > 0) {
-            if (result.charAt(result.length() - 1) == '\n') {
-                result.setCharAt(result.length() - 1, ';');
+            if (endSemiColon) {
+                if (result.charAt(result.length() - 1) == '\n') {
+                    result.setCharAt(result.length() - 1, ';');
+                } else {
+                    result.append(';');
+                }
             } else {
-                result.append(';');
+                if (result.charAt(result.length() - 1) == '\n') {
+                    result.deleteCharAt(result.length() - 1);
+                }
             }
         }
diff -ru orig/com/yahoo/platform/yui/compressor/YUICompressor.java com/yahoo/platform/yui/compressor/YUICompressor.java
--- orig/com/yahoo/platform/yui/compressor/YUICompressor.java	2008-07-10 14:38:00.000000000 +0900
+++ com/yahoo/platform/yui/compressor/YUICompressor.java	2008-07-18 22:22:59.296875000 +0900
@@ -25,6 +25,7 @@
         CmdLineParser.Option nomungeOpt = parser.addBooleanOption("nomunge");
         CmdLineParser.Option linebreakOpt = parser.addStringOption("line-break");
         CmdLineParser.Option preserveSemiOpt = parser.addBooleanOption("preserve-semi");
+        CmdLineParser.Option noEndSemiOpt = parser.addBooleanOption("no-end-semi");
         CmdLineParser.Option disableOptimizationsOpt = parser.addBooleanOption("disable-optimizations");
         CmdLineParser.Option helpOpt = parser.addBooleanOption('h', "help");
         CmdLineParser.Option charsetOpt = parser.addStringOption("charset");
@@ -156,10 +157,11 @@
 
                     boolean munge = parser.getOptionValue(nomungeOpt) == null;
                     boolean preserveAllSemiColons = parser.getOptionValue(preserveSemiOpt) != null;
+                    boolean endSemiColon = parser.getOptionValue(noEndSemiOpt) == null;
                     boolean disableOptimizations = parser.getOptionValue(disableOptimizationsOpt) != null;
 
                     compressor.compress(out, linebreakpos, munge, verbose,
-                            preserveAllSemiColons, disableOptimizations);
+                            preserveAllSemiColons, endSemiColon, disableOptimizations);
 
                 } catch (EvaluatorException e) {
 
@@ -231,6 +233,7 @@
                         + "JavaScript Options\n"
                         + "  --nomunge                 Minify only, do not obfuscate\n"
                         + "  --preserve-semi           Preserve all semicolons\n"
+                        + "  --no-end-semi             Do not add a semicolon to the end of the output\n"
                         + "  --disable-optimizations   Disable all micro optimizations\n\n"
 
                         + "If no input file is specified, it defaults to stdin. In this case, the 'type'\n"
