From 5b6fbc01944c22a12d356af67889b6c066fc4b58 Mon Sep 17 00:00:00 2001 From: Howard Date: Tue, 3 Mar 2020 03:27:07 +0800 Subject: [PATCH] Add ECMA script standard --- ClientDependency.Core/CompositeFiles/JSMin.cs | 154 ++++++++++-------- 1 file changed, 88 insertions(+), 66 deletions(-) diff --git a/ClientDependency.Core/CompositeFiles/JSMin.cs b/ClientDependency.Core/CompositeFiles/JSMin.cs index b1d4ea1..5eaaf78 100644 --- a/ClientDependency.Core/CompositeFiles/JSMin.cs +++ b/ClientDependency.Core/CompositeFiles/JSMin.cs @@ -43,51 +43,51 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ namespace ClientDependency.Core.CompositeFiles -{ - public class JSMin - { - private const int Eof = -1; - private TextReader _sr; - private TextWriter _sw; - private int _theA; - private int _theB; - private int _theLookahead = Eof; - private int _theX = Eof; - private int _theY = Eof; - private int _retStatement = -1; - private bool _start = false; - - [Obsolete("Use the overloads specifying a Stream instead")] - public static string CompressJS(string body) - { - return new JSMin().Minify(body); - } - - public static string CompressJS(Stream stream) - { - var jsMin = new JSMin(); - if (!stream.CanRead) throw new InvalidOperationException("Cannot read input stream"); - if (stream.CanSeek) - { - stream.Position = 0; - } - return jsMin.Minify(new StreamReader(stream)); - } - - [Obsolete("Use the overloads specifying a TextReader instead")] - public string Minify(string src) - { - StringBuilder sb = new StringBuilder(); - using (_sr = new StringReader(src)) - { - using (_sw = new StringWriter(sb)) - { - ExecuteJsMin(); - } - } - return sb.ToString(); - } - +{ + public class JSMin + { + private const int Eof = -1; + private TextReader _sr; + private TextWriter _sw; + private int _theA; + private int _theB; + private int _theLookahead = Eof; + private int _theX = Eof; + private int _theY = Eof; + private int _retStatement = -1; + private bool _start = false; + + [Obsolete("Use the overloads specifying a Stream instead")] + public static string CompressJS(string body) + { + return new JSMin().Minify(body); + } + + public static string CompressJS(Stream stream) + { + var jsMin = new JSMin(); + if (!stream.CanRead) throw new InvalidOperationException("Cannot read input stream"); + if (stream.CanSeek) + { + stream.Position = 0; + } + return jsMin.Minify(new StreamReader(stream)); + } + + [Obsolete("Use the overloads specifying a TextReader instead")] + public string Minify(string src) + { + StringBuilder sb = new StringBuilder(); + using (_sr = new StringReader(src)) + { + using (_sw = new StringWriter(sb)) + { + ExecuteJsMin(); + } + } + return sb.ToString(); + } + public string Minify(TextReader reader) { _sr = reader; @@ -126,7 +126,7 @@ private void ExecuteJsMin() break; case '\n': case '\u2028': - case '\u2029': + case '\u2029': switch (_theB) { case '{': @@ -146,9 +146,9 @@ private void ExecuteJsMin() //Maintain the line break Action(1); break; - case ' ': + case ' ': Action(3); - break; + break; default: if (!_start) { @@ -164,7 +164,7 @@ private void ExecuteJsMin() default: switch (_theB) { - + case ' ': Action(IsAlphanum(_theA) ? 1 : 3); break; @@ -221,8 +221,8 @@ void Action(int d) //process string literals or end of statement and track return statement if (!HandleStringLiteral()) - HandleEndOfStatement(); - + HandleEndOfStatement(); + goto case 3; case 3: _theB = NextCharExcludingComments(); @@ -260,8 +260,8 @@ private bool TrackReturnStatement() { _retStatement = 0; return true; - } - + } + if (_retStatement >= (r.Length - 1)) { //reset when there is a return statement and the next char is not whitespace @@ -287,8 +287,8 @@ private bool TrackReturnStatement() /// private bool HandleEndOfStatement() { - if (_theA != '}') return false; - + if (_theA != '}') return false; + var peek = Peek(); //NOTE: We don't skip over a new line, this is becase in some cases // library managers don't put a semicolon after a } when they have defined a variable as a method, @@ -308,15 +308,15 @@ private bool HandleEndOfStatement() private bool HandleStringLiteral() { if (_theA != '\'' && _theA != '"' && _theA != '`') - return false; - - //only allowed with template strings - var allowLineFeed = _theA == '`'; - - //write the start quote + return false; + + //only allowed with template strings + var allowLineFeed = _theA == '`'; + + //write the start quote Put(_theA); _theA = Get(replaceCr: !allowLineFeed); //don't replace CR here, if we need to deal with that - + for (;;) { //If the A matches B it means the string literal is done @@ -327,14 +327,14 @@ private bool HandleStringLiteral() Put(_theA); //reset, this essentially resets the process - _theA = ' '; + _theA = ' '; break; } var skipRead = false; switch (_theA) - { + { case '\r': case '\n': if (!allowLineFeed) @@ -359,7 +359,7 @@ private bool HandleStringLiteral() Put(_theA); //write the backslash _theA = Get(); //get the escaped char if (_theA == Eof) - throw new Exception($"Error: JSMIN unterminated string literal: {_theA}\n"); + throw new Exception($"Error: JSMIN unterminated string literal: {_theA}\n"); Put(_theA); //write the escaped char _theA = Get(); skipRead = true; //go to beginning of loop @@ -590,6 +590,26 @@ private int NextCharExcludingComments() } } + //ECMA javascript standard comment format + else if (c=='<') + { + if (Peek()=='!') + { + for(;;) + { + c = Get(); + if(c=='-'){ + if(Peek()=='>') + { + Get(); + break; + } + } + } + c = Get(); + } + } + _theY = _theX; _theX = c; return c; @@ -615,6 +635,8 @@ private int Get(bool replaceCr = true) { int c = _theLookahead; _theLookahead = Eof; + //c==Eof means Get() without Peek() + //if c!=Eof means the next char already in Peek(), no need to read again if (c == Eof) { c = _sr.Read(); @@ -662,4 +684,4 @@ private bool IsLineSeparator(int c) } } -} \ No newline at end of file +}