KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > nextapp > echo2 > webrender > util > JavaScriptCompressor


1 /*
2  * This file is part of the Echo Web Application Framework (hereinafter "Echo").
3  * Copyright (C) 2002-2005 NextApp, Inc.
4  *
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with the
9  * License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
13  * the specific language governing rights and limitations under the License.
14  *
15  * Alternatively, the contents of this file may be used under the terms of
16  * either the GNU General Public License Version 2 or later (the "GPL"), or the
17  * GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which
18  * case the provisions of the GPL or the LGPL are applicable instead of those
19  * above. If you wish to allow use of your version of this file only under the
20  * terms of either the GPL or the LGPL, and not to allow others to use your
21  * version of this file under the terms of the MPL, indicate your decision by
22  * deleting the provisions above and replace them with the notice and other
23  * provisions required by the GPL or the LGPL. If you do not delete the
24  * provisions above, a recipient may use your version of this file under the
25  * terms of any one of the MPL, the GPL or the LGPL.
26  */

27
28 package nextapp.echo2.webrender.util;
29
30 /**
31  * Compresses a String containing JavaScript by removing comments and
32  * whitespace.
33  */

34 public class JavaScriptCompressor {
35
36     private static final char LINE_FEED = '\n';
37     private static final char CARRIAGE_RETURN = '\r';
38     private static final char SPACE = ' ';
39     private static final char TAB = '\t';
40
41     /**
42      * Compresses a String containing JavaScript by removing comments and
43      * whitespace.
44      *
45      * @param script the String to compress
46      * @return a compressed version
47      */

48     public static String JavaDoc compress(String JavaDoc script) {
49         JavaScriptCompressor jsc = new JavaScriptCompressor(script);
50         return jsc.outputBuffer.toString();
51     }
52
53     /** Original JavaScript text. */
54     private String JavaDoc script;
55     
56     /**
57      * Compressed output buffer.
58      * This buffer may only be modified by invoking the <code>append()</code>
59      * method.
60      */

61     private StringBuffer JavaDoc outputBuffer;
62     
63     /** Current parser cursor position in original text. */
64     private int pos;
65     
66     /** Character at parser cursor position. */
67     private char ch;
68     
69     /** Last character appended to buffer. */
70     private char lastAppend;
71
72     /** Flag indicating if end-of-buffer has been reached. */
73     private boolean endReached;
74
75     /** Flag indicating whether content has been appended after last identifier. */
76     private boolean contentAppendedAfterLastIdentifier = true;
77
78     /**
79      * Creates a new <code>JavaScriptCompressor</code> instance.
80      *
81      * @param script
82      */

83     private JavaScriptCompressor(String JavaDoc script) {
84         this.script = script;
85         outputBuffer = new StringBuffer JavaDoc(script.length());
86         nextChar();
87
88         while (!endReached) {
89             if (Character.isJavaIdentifierStart(ch)) {
90                 renderIdentifier();
91             } else if (ch == ' ') {
92                 skipWhiteSpace();
93             } else if (isWhitespace()) {
94                 // Compress whitespace
95
skipWhiteSpace();
96             } else if ((ch == '"') || (ch == '\'')) {
97                 // Handle strings
98
renderString();
99             } else if (ch == '/') {
100                 // Handle comments
101
nextChar();
102                 if (ch == '/') {
103                     nextChar();
104                     skipLineComment();
105                 } else if (ch == '*') {
106                     nextChar();
107                     skipBlockComment();
108                 } else {
109                     append('/');
110                 }
111             } else {
112                 append(ch);
113                 nextChar();
114             }
115         }
116     }
117
118     /**
119      * Append character to output.
120      *
121      * @param ch the character to append
122      */

123     private void append(char ch) {
124         lastAppend = ch;
125         outputBuffer.append(ch);
126         contentAppendedAfterLastIdentifier = true;
127     }
128     
129     /**
130      * Determines if current character is whitespace.
131      *
132      * @return true if the character is whitespace
133      */

134     private boolean isWhitespace() {
135         return ch == CARRIAGE_RETURN || ch == SPACE || ch == TAB || ch == LINE_FEED;
136     }
137
138     /**
139      * Load next character.
140      */

141     private void nextChar() {
142         if (!endReached) {
143             if (pos < script.length()) {
144                 ch = script.charAt(pos++);
145             } else {
146                 endReached = true;
147                 ch = 0;
148             }
149         }
150     }
151
152     /**
153      * Adds an identifier to output.
154      */

155     private void renderIdentifier() {
156         if (!contentAppendedAfterLastIdentifier)
157             append(SPACE);
158         append(ch);
159         nextChar();
160         while (Character.isJavaIdentifierPart(ch)) {
161             append(ch);
162             nextChar();
163         }
164         contentAppendedAfterLastIdentifier = false;
165     }
166
167     /**
168      * Adds quoted String starting at current character to output.
169      */

170     private void renderString() {
171         char startCh = ch; // Save quote char
172
append(ch);
173         nextChar();
174         while (true) {
175             if ((ch == LINE_FEED) || (ch == CARRIAGE_RETURN) || (endReached)) {
176                 // JavaScript error: string not terminated
177
return;
178             } else {
179                 if (ch == '\\') {
180                     append(ch);
181                     nextChar();
182                     if ((ch == LINE_FEED) || (ch == CARRIAGE_RETURN) || (endReached)) {
183                         // JavaScript error: string not terminated
184
return;
185                     }
186                     append(ch);
187                     nextChar();
188                 } else {
189                     append(ch);
190                     if (ch == startCh) {
191                         nextChar();
192                         return;
193                     }
194                     nextChar();
195                 }
196             }
197         }
198     }
199
200     /**
201      * Moves cursor past a line comment.
202      */

203     private void skipLineComment() {
204         while ((ch != CARRIAGE_RETURN) && (ch != LINE_FEED)) {
205             if (endReached) {
206                 return;
207             }
208             nextChar();
209         }
210     }
211
212     /**
213      * Moves cursor past a block comment.
214      */

215     private void skipBlockComment() {
216         while (true) {
217             if (endReached) {
218                 return;
219             }
220             if (ch == '*') {
221                 nextChar();
222                 if (ch == '/') {
223                     nextChar();
224                     return;
225                 }
226             } else
227                 nextChar();
228         }
229     }
230     
231     /**
232      * Renders a new line character, provided previously rendered character
233      * is not a newline.
234      */

235     private void renderNewLine() {
236         if (lastAppend != '\n' && lastAppend != '\r') {
237             append('\n');
238         }
239     }
240     
241     /**
242      * Moves cursor past white space (including newlines).
243      */

244     private void skipWhiteSpace() {
245         if (ch == LINE_FEED || ch == CARRIAGE_RETURN) {
246             renderNewLine();
247         } else {
248             append(ch);
249         }
250         nextChar();
251         while (ch == LINE_FEED || ch == CARRIAGE_RETURN || ch == SPACE || ch == TAB) {
252             if (ch == LINE_FEED || ch == CARRIAGE_RETURN) {
253                 renderNewLine();
254             }
255             nextChar();
256         }
257     }
258 }
259
Popular Tags