{"id":2391,"date":"2015-09-21T09:27:26","date_gmt":"2015-09-21T09:27:26","guid":{"rendered":"http:\/\/truelogic.org\/wordpress\/?p=2391"},"modified":"2015-09-21T09:27:26","modified_gmt":"2015-09-21T09:27:26","slug":"minify-javascript-with-python","status":"publish","type":"post","link":"https:\/\/truelogic.org\/wordpress\/2015\/09\/21\/minify-javascript-with-python\/","title":{"rendered":"Minify Javascript with Python"},"content":{"rendered":"            <script type=\"text\/javascript\" src=\"https:\/\/truelogic.org\/wordpress\/wp-content\/plugins\/wordpress-code-snippet\/scripts\/shBrushPython.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>This code uses Python 2.7 so the new features in Python 3.0 are not used here eg. <em>file.peek() .<\/em> The Python 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> Minify(\"test.js\");\r\n<\/pre>\n<p>The modified file will be saved as <i>test.js.min<\/i><br \/>\n<pre class=\"brush: python\">#\r\n# Minify javascript file\r\n# (C) Amit Sengupta, Sep 2015\r\n# Written in Python 2.7\r\n\r\n\r\n\r\nclass Minify():\r\n\r\n    EOF = -1\r\n\r\n    # constructor\r\n    # params: f -f filepath\r\n    #\r\n    def __init__(self, f):\r\n\t\r\n\tif f == &#039;&#039;:\r\n\t    print &quot;No file specified&quot;\r\n\t    return\r\n\t    \r\n\tself.filename = f\t\t# file name\r\n\tself.original_data = &quot;&quot;\t\t# original file data\r\n\tself.modified_data = &quot;&quot;\t\t# data after processing\r\n\tself.is_error = False\t\t# becomes true when error occurs\r\n\tself.error_msg = &quot;&quot;;\t\t# error message\r\n\r\n\ttry:\r\n\t    # open file and read and print original contents\r\n\t    self.file_handle = open(self.filename, &quot;r&quot;)\r\n\t    self.original_data = self.file_handle.read()\r\n\t    self.file_handle.close()\r\n\t    print self.original_data\r\n\r\n\t    \r\n\t    # process file\r\n\t    self.file_handle = open(self.filename, &quot;rb&quot;)\r\n\t    self.doProcess()\r\n\t    self.file_handle.close()\r\n\r\n\t    #write modified data\r\n\t    outfile= self.filename + &quot;.min&quot;\r\n\t    handle = open(outfile, &quot;w&quot;)\r\n\t    handle.write(self.modified_data)\r\n\t    handle.close()\r\n\t    \r\n\r\n\r\n\r\n\texcept IOError as e:\r\n\t    self.is_error = True\r\n\t    self.error_msg = &quot;Error occured:&quot;, e.strerror\r\n\r\n\r\n    # main process \r\n    def doProcess(self):\r\n\tlast_char = -1\t\t\t    # previous byte read\r\n\tthis_char = -1\t\t\t    # current byte read\r\n\tnext_char = -1\t\t\t    # byte read in peek\r\n\tend_process = False\t\t    # terminate flag\r\n\tignore = False\t\t\t    # if false then add byte to final output\r\n\tin_comment = False\t\t    # true when current byte is part of a comment\r\n\tis_double_slash_comment = False\t    # true when current comment is \/\/\r\n\r\n\r\n\twhile (end_process == False):\r\n\t    end_process = self.peek() == Minify.EOF \r\n\t    if end_process:\r\n\t\tbreak\r\n\t    ignore = False\r\n\t    self.this_char = self.file_handle.read(1)\r\n\r\n\t    if self.this_char == &#039;\\t&#039;:\r\n\t\tself.this_char = &#039; &#039;\r\n\t    elif self.this_char == &#039;\\r&#039;:\r\n\t\tself.this_char =- &#039;\\n&#039;\r\n\t    if self.this_char == &#039;\\n&#039;:\r\n\t\tignore = True\r\n\r\n\t    if self.this_char == &#039; &#039;:\r\n\t\tif self.last_char == &#039; &#039; or self.isDelimiter(self.last_char) == 1:\r\n\t\t    ignore = True\r\n\t\telse:\r\n\t\t     end_process = self.peek() == Minify.EOF \r\n\t\t     if not end_process:\r\n\t\t\tself.next_char = self.peek()\r\n\t\t\tif self.isDelimiter(self.next_char) == 1:\r\n\t\t\t    ignore = True\r\n\t\t\t    \r\n\r\n\t    if self.this_char == &#039;\/&#039;:\r\n\t\tself.next_char = self.peek()\r\n\t\tif self.next_char == &#039;\/&#039; or self.next_char == &#039;*&#039;:\r\n\t\t    ignore = True\r\n\t\t    in_comment = True\r\n\t\t    if self.next_char == &#039;\/&#039;:\r\n\t\t\tis_double_slash_comment = True\r\n\t\t    else:\r\n\t\t\tis_double_slash_comment = False\r\n\r\n\r\n\r\n\t    if in_comment == True:\r\n\t\twhile (1):\r\n\t\t    self.this_char = self.file_handle.read(1)\r\n\t\t    if self.this_char == &#039;*&#039;:\r\n\t\t\tself.next_char = self.peek()\r\n\t\t\tif self.next_char == &#039;\/&#039;:\r\n\t\t\t    self.this_char = self.file_handle.read(1)\r\n\t\t\t    in_comment = False\r\n\t\t\t    break;\r\n\t    \t\t\r\n\t\t    if is_double_slash_comment == True and self.this_char == &#039;\\n&#039;:\r\n\t\t\tin_comment = False;\r\n\t\t\tbreak;\r\n\t\t\t\r\n\t\tignore = True\r\n\t\t\r\n\r\n\t    if not ignore:\r\n\t\tself.addToOutput(self.this_char)\r\n\t\r\n\t    self.last_char = self.this_char\r\n\t    \r\n\r\n    \r\n    #\r\n    # add byte to modified data\r\n    # \r\n    def addToOutput(self, c):\r\n\tself.modified_data += str(c);\r\n\r\n\t\r\n    #\r\n    # python 2.x does not support file.peek so make our own\r\n    #\r\n    def peek(self):\r\n\tb = self.file_handle.read(1)\r\n\tself.file_handle.seek(-1, 1)\r\n\r\n\tif not b:\r\n\t    return Minify.EOF\r\n\telse:\r\n\t    return b\r\n\t\r\n    #\r\n    #check if a byte is a delimiter\r\n    #\r\n    def isDelimiter(self, c):\r\n\tretval = 0\r\n\tif c == &#039;(&#039; or c == &#039;,&#039; or c == &#039;=&#039; or c == &#039;:&#039; or \\\r\n           c == &#039;[&#039; or c == &#039;!&#039; or c == &#039;&amp;&#039; or c == &#039;|&#039; or \\\r\n           c == &#039;?&#039; or c == &#039;+&#039; or c == &#039;-&#039; or c == &#039;~&#039; or \\\r\n\t   c == &#039;*&#039; or c == &#039;\/&#039; or c == &#039;{&#039; or c == &#039;\\n&#039; or c == &#039;,&#039;:\r\n\r\n\t   retval = 1\r\n\t   \r\n\treturn retval\r\n\r\n\r\n<\/pre><\/p>\n<p>An example is given below:<br \/>\nOriginal 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","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\/21\/minify-javascript-with-python\/\" title=\"Minify Javascript with Python\">[&#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":[18,297],"tags":[],"class_list":["post-2391","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript","category-python"],"_links":{"self":[{"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts\/2391","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=2391"}],"version-history":[{"count":4,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts\/2391\/revisions"}],"predecessor-version":[{"id":2395,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts\/2391\/revisions\/2395"}],"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=2391"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/categories?post=2391"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/tags?post=2391"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}