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