{"id":2385,"date":"2015-09-18T17:46:56","date_gmt":"2015-09-18T17:46:56","guid":{"rendered":"http:\/\/truelogic.org\/wordpress\/?p=2385"},"modified":"2015-09-18T17:52:40","modified_gmt":"2015-09-18T17:52:40","slug":"minify-javascript-with-c","status":"publish","type":"post","link":"https:\/\/truelogic.org\/wordpress\/2015\/09\/18\/minify-javascript-with-c\/","title":{"rendered":"Minify Javascript with C#"},"content":{"rendered":"            <script type=\"text\/javascript\" src=\"https:\/\/truelogic.org\/wordpress\/wp-content\/plugins\/wordpress-code-snippet\/scripts\/shBrushCSharp.js\"><\/script>\n            <script type=\"text\/javascript\" src=\"https:\/\/truelogic.org\/wordpress\/wp-content\/plugins\/wordpress-code-snippet\/scripts\/shBrushJScript.js\"><\/script>\n<p>The code below compresses and minifies javascript files. Minification is not the same as obfuscation. Minification removes all whitespace , comments and needless characters so that the end result is much smaller and is more difficult to read . Obfuscation does minification as well as mangles variables and functions so that the code is completely unreadable.<\/p>\n<p>The C# class takes in a javascript file and minifies and writes it out to another file.<br \/>\nThe class can be called in a single line of code :<\/p>\n<pre>\r\n Minify js = new Minify(@\"c:\\myfiles\\test.js\");\r\n<\/pre>\n<p>The modified file will be saved as <i>c:\\myfiles\\test.js.min<\/i><\/p>\n<p><pre class=\"brush: csharp\">using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\n\r\nnamespace JSMinify\r\n{\r\n    public class Minify\r\n    {\r\n        private string mFileName = &quot;&quot;;              \/\/ file to process\r\n        private string mOriginalData = &quot;&quot;;           \/\/ data from original file\r\n        private string mModifiedData = &quot;&quot;;          \/\/ processed data\r\n        private bool mIsError = false;               \/\/ becomes true if any error happens\r\n        private string mErr = &quot;&quot;;                    \/\/ error message \r\n        private BinaryReader mReader = null;         \/\/ stream to process the file byte by byte\r\n\r\n        private const int EOF = -1;                 \/\/ for end of file\r\n\r\n        \/\/\/ &lt;summary&gt;\r\n        \/\/\/ Constructor - does all the processing\r\n        \/\/\/ &lt;\/summary&gt;\r\n        \/\/\/ &lt;param name=&quot;f&quot;&gt;file path&lt;\/param&gt;\r\n        public Minify(string f) {\r\n\r\n            try\r\n            {\r\n                if (File.Exists(f))\r\n                {\r\n                    mFileName = f;\r\n                    \r\n                    \/\/read contents completely. This is only for test purposes. The actual processing is done by another stream\r\n                    StreamReader rdr = new StreamReader(mFileName);\r\n                    mOriginalData = rdr.ReadToEnd();\r\n                    rdr.Close();\r\n\r\n                    mReader = new BinaryReader(new FileStream(mFileName, FileMode.Open));\r\n                    doProcess();\r\n                    mReader.Close();\r\n\r\n                    \/\/write modified data\r\n                    string outFile = mFileName + &quot;.min&quot;;\r\n                    StreamWriter wrt = new StreamWriter(outFile);\r\n                    wrt.Write(mModifiedData);\r\n                    wrt.Close();\r\n\r\n                }\r\n                else {\r\n                    mIsError = true;\r\n                    mErr = &quot;File does not exist&quot;;\r\n                }\r\n\r\n            }\r\n            catch (Exception ex) {\r\n                mIsError = true;\r\n                mErr = ex.Message;\r\n            }\r\n        }\r\n\r\n        \/\/\/ &lt;summary&gt;\r\n        \/\/\/ Main process\r\n        \/\/\/ &lt;\/summary&gt;\r\n        private void doProcess() { \r\n            int lastChar = 1;                   \/\/ current byte read\r\n            int thisChar = -1;                  \/\/ previous byte read\r\n            int nextChar = -1;                  \/\/ byte read in peek()\r\n            bool endProcess = false;            \/\/ loop control\r\n            bool ignore = false;                \/\/ if false then add byte to final output\r\n            bool inComment = false;             \/\/ true when current bytes are part of a comment\r\n            bool isDoubleSlashComment = false;  \/\/ &#039;\/\/&#039; comment\r\n\r\n\r\n            \/\/ main processing loop\r\n            while (!endProcess) {\r\n                endProcess = (mReader.PeekChar() == -1);    \/\/ check for EOF before reading\r\n                if (endProcess)\r\n                    break;\r\n\r\n                ignore = false;\r\n                thisChar = mReader.ReadByte();\r\n                \r\n                if (thisChar == &#039;\\t&#039;)\r\n                    thisChar = &#039; &#039;;\r\n                else if (thisChar == &#039;\\t&#039;)\r\n                    thisChar = &#039;\\n&#039;;\r\n                else if (thisChar == &#039;\\r&#039;)\r\n                    thisChar = &#039;\\n&#039;;\r\n\r\n                if (thisChar == &#039;\\n&#039;)\r\n                    ignore = true;\r\n\r\n                if (thisChar == &#039; &#039;)\r\n                {\r\n                    if ((lastChar == &#039; &#039;) || isDelimiter(lastChar) == 1)\r\n                        ignore = true;\r\n                    else {\r\n                        endProcess = (mReader.PeekChar() == -1); \/\/ check for EOF\r\n                        if (!endProcess)\r\n                        {\r\n                            nextChar = mReader.PeekChar();\r\n                            if (isDelimiter(nextChar) == 1)\r\n                                ignore = true;\r\n                        }\r\n                    }\r\n                }\r\n\r\n\r\n                if (thisChar == &#039;\/&#039;)\r\n                {\r\n                    nextChar = mReader.PeekChar();\r\n                    if (nextChar == &#039;\/&#039; || nextChar == &#039;*&#039;)\r\n                    {\r\n                        ignore = true;\r\n                        inComment = true;\r\n                        if (nextChar == &#039;\/&#039;)\r\n                            isDoubleSlashComment = true;\r\n                        else\r\n                            isDoubleSlashComment = false;\r\n                    }\r\n\r\n\r\n                }\r\n\r\n                \/\/ ignore all characters till we reach end of comment\r\n                if (inComment) {\r\n                    while (true) {\r\n                        thisChar = mReader.ReadByte();\r\n                        if (thisChar == &#039;*&#039;) {\r\n                            nextChar = mReader.PeekChar();\r\n                            if (nextChar == &#039;\/&#039;)\r\n                            {\r\n                                thisChar = mReader.ReadByte();\r\n                                inComment = false;\r\n                                break;\r\n                            }\r\n                        }\r\n                        if (isDoubleSlashComment &amp;&amp; thisChar == &#039;\\n&#039;) {\r\n                                inComment = false;\r\n                                break;\r\n                        }\r\n\r\n                     } \/\/ while (true)\r\n                    ignore = true;  \r\n                } \/\/ if (inComment) \r\n                \r\n\r\n                if (!ignore)\r\n                    addToOutput(thisChar);\r\n                    \r\n                lastChar = thisChar;\r\n            } \/\/ while (!endProcess) \r\n        }\r\n\r\n\r\n        \/\/\/ &lt;summary&gt;\r\n        \/\/\/ Add character to modified data string\r\n        \/\/\/ &lt;\/summary&gt;\r\n        \/\/\/ &lt;param name=&quot;c&quot;&gt;char to add&lt;\/param&gt;\r\n        private void addToOutput(int c)\r\n        {\r\n            mModifiedData += (char) c;\r\n        }\r\n\r\n\r\n        \/\/\/ &lt;summary&gt;\r\n        \/\/\/ Original data from file\r\n        \/\/\/ &lt;\/summary&gt;\r\n        \/\/\/ &lt;returns&gt;&lt;\/returns&gt;\r\n        public string getOriginalData()\r\n        {\r\n            return mOriginalData;\r\n        }\r\n\r\n        \/\/\/ &lt;summary&gt;\r\n        \/\/\/ Modified data after processing\r\n        \/\/\/ &lt;\/summary&gt;\r\n        \/\/\/ &lt;returns&gt;&lt;\/returns&gt;\r\n        public string getModifiedData()\r\n        {\r\n            return mModifiedData;\r\n        }\r\n\r\n        \/\/\/ &lt;summary&gt;\r\n        \/\/\/ Check if a byte is alphanumeric\r\n        \/\/\/ &lt;\/summary&gt;\r\n        \/\/\/ &lt;param name=&quot;c&quot;&gt;byte to check&lt;\/param&gt;\r\n        \/\/\/ &lt;returns&gt;retval - 1 if yes. else 0&lt;\/returns&gt;\r\n        private int isAlphanumeric(int c)\r\n        {\r\n            int retval = 0;\r\n\r\n            if ((c &gt;= &#039;a&#039; &amp;&amp; c &lt;= &#039;z&#039;) ||\r\n                (c &gt;= &#039;0&#039; &amp;&amp; c &lt;= &#039;9&#039;) ||\r\n                (c &gt;= &#039;A&#039; &amp;&amp; c &lt;= &#039;Z&#039;) ||\r\n                c == &#039;_&#039; || c == &#039;$&#039; || c == &#039;\\\\&#039; || c &gt; 126)\r\n                retval = 1;\r\n\r\n            return retval;\r\n\r\n        }\r\n\r\n        \/\/\/ &lt;summary&gt;\r\n        \/\/\/ Check if a byte is a delimiter \r\n        \/\/\/ &lt;\/summary&gt;\r\n        \/\/\/ &lt;param name=&quot;c&quot;&gt;byte to check&lt;\/param&gt;\r\n        \/\/\/ &lt;returns&gt;retval - 1 if yes. else 0&lt;\/returns&gt;\r\n        private int isDelimiter(int c)\r\n        {\r\n            int retval = 0;\r\n\r\n            if (c == &#039;(&#039; || c == &#039;,&#039; || c == &#039;=&#039; || c == &#039;:&#039; ||\r\n                c == &#039;[&#039; || c == &#039;!&#039; || c == &#039;&amp;&#039; || c == &#039;|&#039; ||\r\n                c == &#039;?&#039; || c == &#039;+&#039; || c == &#039;-&#039; || c == &#039;~&#039; ||\r\n                c == &#039;*&#039; || c == &#039;\/&#039; || c == &#039;{&#039; || c == &#039;\\n&#039; ||\r\n                c == &#039;,&#039; \r\n            )\r\n            {\r\n                retval = 1;\r\n            }\r\n\r\n            return retval;\r\n\r\n        }\r\n\r\n\r\n\r\n    }\r\n}\r\n<\/pre><\/p>\n<p>An example is given below:<\/p>\n<p>Original file:<br \/>\n<pre class=\"brush: js\">\/* jshint define: false *\/\r\n\r\n\/**\r\n * @file This plugin adds on primitive Object (like string, number, array ...) additionnals methods\r\n * @version 1.0\r\n * @author Julien Roche\r\n * @copyright MIT\r\n *\/\r\n\r\n(function(){\r\n\t&quot;use strict&quot;;\r\n\r\n\tfunction definition($){\r\n\t\t\/* String part *\/\r\n\t\tString.prototype.endWith = function (needle) { \r\n\t\t\treturn this &amp;&amp; this.match(needle + &quot;$&quot;) == needle;\r\n\t\t};\r\n\t\t\r\n        String.prototype.repeat = function (num) { \r\n\/\/\t\t\treturn new Array(num + 1).join(this);\r\n\t\t\tvar arr = [];\r\n\t\t\tarr.length = num + 1;\r\n\t\t\treturn arr.join(this);\r\n\t\t};\r\n\t\t\r\n        String.prototype.startWith = function (needle) {\r\n\t\t\treturn this &amp;&amp; this.match(&quot;^&quot; + needle) == needle;\r\n\t\t};\r\n\t\t\r\n\t\t\/* Number part *\/\r\n\t\tNumber.prototype.toPaddedString = function (length, radix) {\r\n\t\t\tvar string = this.toString(radix || 10), slength = string.length;\r\n\t\t\tfor (var i = 0; i &lt; (length - slength); i++) {\r\n\t\t\t\tstring = &quot;0&quot; + string;\r\n\t\t\t} \r\n\t\t\treturn string;\r\n\t\t};\r\n\t\t\r\n\t\t\/* Array part *\/\r\n\t\t\r\n\t\t\/\/ See http:\/\/www.to-string.com\/2012\/05\/29\/fixing-splice-in-older-versions-of-internet-explorer-8-and-olders\/\r\n\t\tif (document.documentMode &amp;&amp; document.documentMode &lt; 9) {\r\n\t\t\t\/\/ save original function of splice\r\n\t\t\tvar originalSplice = Array.prototype.splice;\r\n\t\t\t\r\n\t\t\t\/\/ provide a new implementation\r\n\t\t\tArray.prototype.splice = function() {\r\n\t\t\t\t\r\n\t\t\t\t\/\/ since we can&#039;t modify &#039;arguments&#039; array, \r\n\t\t\t\t\/\/ let&#039;s create a new one and copy all elements of &#039;arguments&#039; into it\r\n\t\t\t\tvar arr = [],\r\n\t\t\t\t\ti = 0,\r\n\t\t\t\t\tmax = arguments.length;\r\n\t\t\t\t\r\n\t\t\t\tfor (; i &lt; max; i++){\r\n\t\t\t\t\tarr.push(arguments[i]);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\t\/\/ if this function had only one argument\r\n\t\t\t\t\/\/ compute &#039;deleteCount&#039; and push it into arr\r\n\t\t\t\tif (arr.length==1) {\r\n\t\t\t\t\tarr.push(this.length - arr[0]);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\t\/\/ invoke original splice() with our new arguments array\r\n\t\t\t\treturn originalSplice.apply(this, arr);\r\n\t\t\t};\r\n\t\t}\r\n\t\t\r\n\t\t\/\/ See https:\/\/developer.mozilla.org\/en-US\/docs\/JavaScript\/Reference\/Global_Objects\/Array\/forEach\r\n\t\tif(!Array.prototype.forEach) {\r\n\t\t\tArray.prototype.forEach = function forEach(callback, thisArg) {\r\n\t\t\t\tvar T, k;\r\n\r\n\t\t\t\tif(this == null) {\r\n\t\t\t\t\tthrow new TypeError(&quot;this is null or not defined&quot;);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t\/\/ 1. Let O be the result of calling ToObject passing the |this| value as the argument.\r\n\t\t\t\tvar O = Object(this);\r\n\r\n\t\t\t\t\/\/ 2. Let lenValue be the result of calling the Get internal method of O with the argument &quot;length&quot;.\r\n\t\t\t\t\/\/ 3. Let len be ToUint32(lenValue).\r\n\t\t\t\tvar len = O.length &gt;&gt;&gt; 0;\r\n\t\t\t\t\/\/ Hack to convert O.length to a UInt32\r\n\r\n\t\t\t\t\/\/ 4. If IsCallable(callback) is false, throw a TypeError exception.\r\n\t\t\t\t\/\/ See: http:\/\/es5.github.com\/#x9.11\r\n\t\t\t\tif( {}.toString.call(callback) !== &quot;[object Function]&quot;) {\r\n\t\t\t\t\tthrow new TypeError(callback + &quot; is not a function&quot;);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t\/\/ 5. If thisArg was supplied, let T be thisArg; else let T be undefined.\r\n\t\t\t\tif(thisArg) {\r\n\t\t\t\t\tT = thisArg;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t\/\/ 6. Let k be 0\r\n\t\t\t\tk = 0;\r\n\r\n\t\t\t\t\/\/ 7. Repeat, while k &lt; len\r\n\t\t\t\twhile(k &lt; len) {\r\n\r\n\t\t\t\t\tvar kValue;\r\n\r\n\t\t\t\t\t\/\/ a. Let Pk be ToString(k).\r\n\t\t\t\t\t\/\/   This is implicit for LHS operands of the in operator\r\n\t\t\t\t\t\/\/ b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.\r\n\t\t\t\t\t\/\/   This step can be combined with c\r\n\t\t\t\t\t\/\/ c. If kPresent is true, then\r\n\t\t\t\t\tif(Object.prototype.hasOwnProperty.call(O, k)) {\r\n\r\n\t\t\t\t\t\t\/\/ i. Let kValue be the result of calling the Get internal method of O with argument Pk.\r\n\t\t\t\t\t\tkValue = O[k];\r\n\r\n\t\t\t\t\t\t\/\/ ii. Call the Call internal method of callback with T as the this value and\r\n\t\t\t\t\t\t\/\/ argument list containing kValue, k, and O.\r\n\t\t\t\t\t\tcallback.call(T, kValue, k, O);\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\/\/ d. Increase k by 1.\r\n\t\t\t\t\tk++;\r\n\t\t\t\t}\r\n\t\t\t\t\/\/ 8. return undefined\r\n\t\t\t};\r\n\t\t}\r\n\t}\r\n\r\n\tif (typeof module === &quot;object&quot; &amp;&amp; typeof module.exports === &quot;object&quot;) {\r\n\t\t\/\/ Node approach\r\n\t\tdefinition();\r\n\r\n\t} else if (typeof define === &quot;function&quot; &amp;&amp; define.amd) {\r\n\t\t\/\/ AMD approach\r\n\t\tdefine(&quot;prototype&quot;, [], definition);\r\n\r\n\t} else if (window.jQuery) {\r\n\t\t\/\/ Classical way\r\n\t\tdefinition();\r\n\t}\r\n}());<\/pre><\/p>\n<p>Minified file:<br \/>\n<pre class=\"brush: js\">(function(){&quot;use strict&quot;;function definition($){String.prototype.endWith=function(needle){return this&amp;&amp;this.match(needle+&quot;$&quot;)==needle;};String.prototype.repeat=function(num){var arr=[];arr.length=num+1;return arr.join(this);};String.prototype.startWith=function(needle){return this&amp;&amp;this.match(&quot;^&quot;+needle)==needle;};Number.prototype.toPaddedString=function(length,radix){var string=this.toString(radix||10),slength=string.length;for(var i=0; i &lt;(length-slength); i++){string=&quot;0&quot;+string;} return string;};if(document.documentMode&amp;&amp;document.documentMode &lt; 9){var originalSplice=Array.prototype.splice;Array.prototype.splice=function(){var arr=[],i=0,max=arguments.length;for(; i &lt; max; i++){arr.push(arguments[i]);}if(arr.length==1){arr.push(this.length-arr[0]);}return originalSplice.apply(this,arr);};}if(!Array.prototype.forEach){Array.prototype.forEach=function forEach(callback,thisArg){var T,k;if(this==null){throw new TypeError(&quot;this is null or not defined&quot;);}var O=Object(this);var len=O.length &gt;&gt;&gt; 0;if({}.toString.call(callback)!==&quot;[object Function]&quot;){throw new TypeError(callback+&quot; is not a function&quot;);}if(thisArg){T=thisArg;}k=0;while(k &lt; len){var kValue;if(Object.prototype.hasOwnProperty.call(O,k)){kValue=O[k];callback.call(T,kValue,k,O);}k++;}};}}if(typeof module===&quot;object&quot;&amp;&amp;typeof module.exports===&quot;object&quot;){definition();} else if(typeof define===&quot;function&quot;&amp;&amp;define.amd){define(&quot;prototype&quot;,[],definition);} else if(window.jQuery){definition();}}());<\/pre><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p>The code below compresses and minifies javascript files. Minification is not the same as obfuscation. Minification removes all whitespace , comments and needless characters so <a class=\"mh-excerpt-more\" href=\"https:\/\/truelogic.org\/wordpress\/2015\/09\/18\/minify-javascript-with-c\/\" title=\"Minify Javascript with C#\">[&#8230;]<\/a><\/p>\n<\/div>","protected":false},"author":1,"featured_media":2388,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17,18],"tags":[],"class_list":["post-2385","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-asp-net","category-javascript"],"_links":{"self":[{"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts\/2385","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/comments?post=2385"}],"version-history":[{"count":4,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts\/2385\/revisions"}],"predecessor-version":[{"id":2390,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts\/2385\/revisions\/2390"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/media\/2388"}],"wp:attachment":[{"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/media?parent=2385"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/categories?post=2385"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/tags?post=2385"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}