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.
This code uses Python 2.7 so the new features in Python 3.0 are not used here eg. file.peek() . The Python class takes in a javascript file and minifies and writes it out to another file.
The class can be called in a single line of code :
Minify("test.js");
The modified file will be saved as test.js.min
# # Minify javascript file # (C) Amit Sengupta, Sep 2015 # Written in Python 2.7 class Minify(): EOF = -1 # constructor # params: f -f filepath # def __init__(self, f): if f == '': print "No file specified" return self.filename = f # file name self.original_data = "" # original file data self.modified_data = "" # data after processing self.is_error = False # becomes true when error occurs self.error_msg = ""; # error message try: # open file and read and print original contents self.file_handle = open(self.filename, "r") self.original_data = self.file_handle.read() self.file_handle.close() print self.original_data # process file self.file_handle = open(self.filename, "rb") self.doProcess() self.file_handle.close() #write modified data outfile= self.filename + ".min" handle = open(outfile, "w") handle.write(self.modified_data) handle.close() except IOError as e: self.is_error = True self.error_msg = "Error occured:", e.strerror # main process def doProcess(self): last_char = -1 # previous byte read this_char = -1 # current byte read next_char = -1 # byte read in peek end_process = False # terminate flag ignore = False # if false then add byte to final output in_comment = False # true when current byte is part of a comment is_double_slash_comment = False # true when current comment is // while (end_process == False): end_process = self.peek() == Minify.EOF if end_process: break ignore = False self.this_char = self.file_handle.read(1) if self.this_char == '\t': self.this_char = ' ' elif self.this_char == '\r': self.this_char =- '\n' if self.this_char == '\n': ignore = True if self.this_char == ' ': if self.last_char == ' ' or self.isDelimiter(self.last_char) == 1: ignore = True else: end_process = self.peek() == Minify.EOF if not end_process: self.next_char = self.peek() if self.isDelimiter(self.next_char) == 1: ignore = True if self.this_char == '/': self.next_char = self.peek() if self.next_char == '/' or self.next_char == '*': ignore = True in_comment = True if self.next_char == '/': is_double_slash_comment = True else: is_double_slash_comment = False if in_comment == True: while (1): self.this_char = self.file_handle.read(1) if self.this_char == '*': self.next_char = self.peek() if self.next_char == '/': self.this_char = self.file_handle.read(1) in_comment = False break; if is_double_slash_comment == True and self.this_char == '\n': in_comment = False; break; ignore = True if not ignore: self.addToOutput(self.this_char) self.last_char = self.this_char # # add byte to modified data # def addToOutput(self, c): self.modified_data += str(c); # # python 2.x does not support file.peek so make our own # def peek(self): b = self.file_handle.read(1) self.file_handle.seek(-1, 1) if not b: return Minify.EOF else: return b # #check if a byte is a delimiter # def isDelimiter(self, c): retval = 0 if c == '(' or c == ',' or c == '=' or c == ':' or \ c == '[' or c == '!' or c == '&' or c == '|' or \ c == '?' or c == '+' or c == '-' or c == '~' or \ c == '*' or c == '/' or c == '{' or c == '\n' or c == ',': retval = 1 return retval
An example is given below:
Original File:
/* jshint define: false */ /** * @file This plugin adds on primitive Object (like string, number, array ...) additionnals methods * @version 1.0 * @author Julien Roche * @copyright MIT */ (function(){ "use strict"; function definition($){ /* String part */ String.prototype.endWith = function (needle) { return this && this.match(needle + "$") == needle; }; String.prototype.repeat = function (num) { // return new Array(num + 1).join(this); var arr = []; arr.length = num + 1; return arr.join(this); }; String.prototype.startWith = function (needle) { return this && this.match("^" + needle) == needle; }; /* Number part */ Number.prototype.toPaddedString = function (length, radix) { var string = this.toString(radix || 10), slength = string.length; for (var i = 0; i < (length - slength); i++) { string = "0" + string; } return string; }; /* Array part */ // See http://www.to-string.com/2012/05/29/fixing-splice-in-older-versions-of-internet-explorer-8-and-olders/ if (document.documentMode && document.documentMode < 9) { // save original function of splice var originalSplice = Array.prototype.splice; // provide a new implementation Array.prototype.splice = function() { // since we can't modify 'arguments' array, // let's create a new one and copy all elements of 'arguments' into it var arr = [], i = 0, max = arguments.length; for (; i < max; i++){ arr.push(arguments[i]); } // if this function had only one argument // compute 'deleteCount' and push it into arr if (arr.length==1) { arr.push(this.length - arr[0]); } // invoke original splice() with our new arguments array return originalSplice.apply(this, arr); }; } // See https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach if(!Array.prototype.forEach) { Array.prototype.forEach = function forEach(callback, thisArg) { var T, k; if(this == null) { throw new TypeError("this is null or not defined"); } // 1. Let O be the result of calling ToObject passing the |this| value as the argument. var O = Object(this); // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". // 3. Let len be ToUint32(lenValue). var len = O.length >>> 0; // Hack to convert O.length to a UInt32 // 4. If IsCallable(callback) is false, throw a TypeError exception. // See: http://es5.github.com/#x9.11 if( {}.toString.call(callback) !== "[object Function]") { throw new TypeError(callback + " is not a function"); } // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. if(thisArg) { T = thisArg; } // 6. Let k be 0 k = 0; // 7. Repeat, while k < len while(k < len) { var kValue; // a. Let Pk be ToString(k). // This is implicit for LHS operands of the in operator // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. // This step can be combined with c // c. If kPresent is true, then if(Object.prototype.hasOwnProperty.call(O, k)) { // i. Let kValue be the result of calling the Get internal method of O with argument Pk. kValue = O[k]; // ii. Call the Call internal method of callback with T as the this value and // argument list containing kValue, k, and O. callback.call(T, kValue, k, O); } // d. Increase k by 1. k++; } // 8. return undefined }; } } if (typeof module === "object" && typeof module.exports === "object") { // Node approach definition(); } else if (typeof define === "function" && define.amd) { // AMD approach define("prototype", [], definition); } else if (window.jQuery) { // Classical way definition(); } }());
Minified File:
(function(){"use strict";function definition($){String.prototype.endWith=function(needle){return this&&this.match(needle+"$")==needle;};String.prototype.repeat=function(num){var arr=[];arr.length=num+1;return arr.join(this);};String.prototype.startWith=function(needle){return this&&this.match("^"+needle)==needle;};Number.prototype.toPaddedString=function(length,radix){var string=this.toString(radix||10),slength=string.length;for(var i=0; i <(length-slength); i++){string="0"+string;} return string;};if(document.documentMode&&document.documentMode < 9){var originalSplice=Array.prototype.splice;Array.prototype.splice=function(){var arr=[],i=0,max=arguments.length;for(; i < 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("this is null or not defined");}var O=Object(this);var len=O.length >>> 0;if({}.toString.call(callback)!=="[object Function]"){throw new TypeError(callback+" is not a function");}if(thisArg){T=thisArg;}k=0;while(k < len){var kValue;if(Object.prototype.hasOwnProperty.call(O,k)){kValue=O[k];callback.call(T,kValue,k,O);}k++;}};}}if(typeof module==="object"&&typeof module.exports==="object"){definition();} else if(typeof define==="function"&&define.amd){define("prototype",[],definition);} else if(window.jQuery){definition();}}());
Leave a Reply