View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.IO;

/// <summary>
/// 提供压缩 JavaScript 代码的能力。
/// </summary>
public sealed class JavaScriptMinifier
{
#region 私有字段

private const int EOF = -1;

private readonly StringBuilder _JsBuilder;
private readonly TextReader _JsReader;
private int _TheA = Convert.ToInt32('\n');
private int _TheB;
private int _TheLookahead = EOF;

#endregion

#region 构造函数

/// <summary>
/// 初始化 <see cref="JavaScriptMinifier"/> 类的新实例。
/// </summary>
/// <param name="jsReader">包含要压缩的 JavaScript 代码的 <see cref="TextReader"/></param>
private JavaScriptMinifier(TextReader jsReader)
{
if (jsReader == null) throw new ArgumentNullException("jsReader");

this._JsReader = jsReader;
this._JsBuilder = new StringBuilder();
}

#endregion

#region 静态方法

/// <summary>
/// 压缩指定的 JavaScript 代码。
/// </summary>
/// <param name="js">包含要压缩的 JavaScript 代码的 <see cref="StringBuilder"/></param>
/// <returns>返回包含压缩后的 JavaScript 代码的 <see cref="StringBuilder"/></returns>
public static StringBuilder Minify(StringBuilder js) { return Minify(new StringReader(js.ToString())); }

/// <summary>
/// 压缩指定的 JavaScript 代码。
/// </summary>
/// <param name="jsCode">要压缩的 JavaScript 代码。</param>
/// <returns>返回包含压缩后的 JavaScript 代码的 <see cref="StringBuilder"/></returns>
public static StringBuilder Minify(string jsCode) { return Minify(new StringReader(jsCode)); }

/// <summary>
/// 压缩指定的 JavaScript 代码。
/// </summary>
/// <param name="jsReader">包含要压缩的 JavaScript 代码的 <see cref="TextReader"/></param>
/// <returns>返回包含压缩后的 JavaScript 代码的 <see cref="StringBuilder"/></returns>
public static StringBuilder Minify(TextReader jsReader)
{
JavaScriptMinifier jsmin
= new JavaScriptMinifier(jsReader);

jsmin._Jsmin();

return jsmin._JsBuilder;
}

#endregion

#region 私有方法

private void _Jsmin()
{
this._Action(3);

while (this._TheA != EOF)
{
switch ((Char)this._TheA)
{
case ' ':
if (_IsAlphanum(this._TheB)) this._Action(1);
else this._Action(2);

break;
case '\n':
switch ((Char)this._TheB)
{
case '{':
case '[':
case '(':
case '+':
case '-':
this._Action(1);

break;
case ' ':
this._Action(3);

break;
default:
if (_IsAlphanum(this._TheB)) this._Action(1);
else this._Action(2);

break;
}

break;
default:
switch ((Char)this._TheB)
{
case ' ':
if (_IsAlphanum(this._TheA))
{
this._Action(1);

break;
}

this._Action(3);

break;
case '\n':
switch ((Char)this._TheA)
{
case '}':
case ']':
case ')':
case '+':
case '-':
case '"':
case '\'':
this._Action(1);

break;
default:
if (_IsAlphanum(this._TheA)) this._Action(1);
else this._Action(3);

break;
}

break;
default:
this._Action(1);

break;
}

break;
}
}
}

private void _Action(int d)
{
if (d <= 1) this._Put(this._TheA);
if (d <= 2)
{
this._TheA = this._TheB;

if (this._TheA == '\'' || this._TheA == '"')
{
for (; ; )
{
this._Put(this._TheA);
this._TheA = this._Get();

if (this._TheA == this._TheB) break;
if (this._TheA <= '\n') throw new Exception(string.Format("Error: JSMIN unterminated string literal: {0}", this._TheA));
if (this._TheA != '\\') continue;

this._Put(this._TheA);
this._TheA = this._Get();
}
}
}

if (d > 3) return;

this._TheB = this._Next();

if (this._TheB != '/' || ((((((((((((this._TheA != '(' && this._TheA != ',') && this._TheA != '=') && this._TheA != '[') && this._TheA != '!') && this._TheA != ':') && this._TheA != '&') && this._TheA != '|') && this._TheA != '?') && this._TheA != '{') && this._TheA != '}') && this._TheA != ';') && this._TheA != '\n')) return;

this._Put(this._TheA);
this._Put(this._TheB);

for (; ; )
{
this._TheA = this._Get();

if (this._TheA == '/') break;

if (this._TheA == '\\')
{
this._Put(this._TheA);
this._TheA = this._Get();
}
else if (this._TheA <= '\n') throw new Exception(string.Format("Error: JSMIN unterminated Regular Expression literal : {0}.", this._TheA));

this._Put(this._TheA);
}

this._TheB = this._Next();
}

private int _Next()
{
int c = this._Get();
const int s = (int)'*';

if (c == '/')
{
switch ((Char)this._Peek())
{
case '/':
for (; ; )
{
c
= this._Get();

if (c <= '\n') return c;
}
case '*':
this._Get();

for (; ; )
{
switch (this._Get())
{
case s:
if (this._Peek() == '/')
{
this._Get();

return Convert.ToInt32(' ');
}

break;
case EOF:
throw new Exception("Error: JSMIN Unterminated comment.");
}
}
default:
return c;
}
}

return c;
}

private int _Peek()
{
this._TheLookahead = this._Get();

return this._TheLookahead;
}

private int _Get()
{
int c = this._TheLookahead;
this._TheLookahead = EOF;

if (c == EOF) c = this._JsReader.Read();

return c >= ' ' || c == '\n' || c == EOF ? c : (c == '\r' ? '\n' : ' ');
}

private void _Put(int c) { this._JsBuilder.Append((char)c); }

private static bool _IsAlphanum(int c) { return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' || c > 126); }

#endregion
}
posted on 2011-05-19 12:02  Dacia  阅读(654)  评论(0编辑  收藏  举报