/*** cn.newweapon.JsFormatter*/packagecn.newweapon;importjava.io.File;importjava.io.FileReader;importjava.io.FileWriter;importjava.io.FilenameFilter;importjava.io.IOException;importjava.util.ArrayList;importjava.util.Iterator;importjava.util.List;importjava.util.regex.Pattern;/***@authorNewweapon @ ustc [Email: newweapon111 (at) gmail.com]
*@version0.0.1
* @Created 20071015
*
* @TODO 1. user can specify the formatted file name;
* 2. User can located the formatted files to a specified folder.
* 3. If a file is formatted partly already. Delete all blank characters first, and then format the file.
*/publicclassJsFormatter {/*============ constants begin ===================*//**Usage*/publicstaticString USAGE="Usage: JsFormatter -d path/directory JsFormatter -f path/filename.js";/**Type: Directory = "0"; File = "1"*/publicinterfaceType {/**Directory: 0*/publicstaticString DIRECTORY="0";/**File: 1*/publicstaticString FILE="1";
}/*============ constants end ===================*//*** Entry point of the project.
*
*@paramargs Like "-d /path/directory" or "-f /path/file.js"*/publicstaticvoidmain(String[] args) {
String startMsg="Processing...";
String finishMsg="Finished.";//Parameters check.if(args.length!=2) {
System.err.println(USAGE);return;
}//Get the two parameters.String type=args[0];
String path=args[1];//Parameters check.if("-d".equals(type)||"--directory".equals(type)) {
type=Type.DIRECTORY;
}elseif("-f".equals(type)||"--file".equals(type)) {
type=Type.FILE;
}else{
System.err.println(USAGE);return;
}//Check file typeif(Type.FILE.equals(type)) {if(path.length()<=3||!isJsFile(path)) {
System.err.println("The file must be a JS file.");return;
}
}//Start messageSystem.out.println(startMsg);//Format file(s)try{if(Type.FILE.equals(type)) {
formatFile(path);
}else{
ListjsFileList=getJsFileList(path);
Iteratorit=jsFileList.iterator();while(it.hasNext()) {
formatFile(it.next());
}
finishMsg+="("+jsFileList.size()+"file(s) formatted)";
}
}catch(Exception e) {
e.printStackTrace();return;
}//Finish messageSystem.out.println(finishMsg);
}/*** Format a JS file.
*
*@paramfileName The file name of the file which is to be formatted.
*@returnString The formatted string.
*@throwsIOException Exception when open, read and write file.*/privatestaticvoidformatFile(String fileName)throwsIOException {
String formattedFileName=fileName+".formatted";
FileReader fr=newFileReader(fileName);
FileWriter fw=newFileWriter(formattedFileName);
String lastWord="";intforCount=0;intquoteCount=0;intsigleQuoteCount=0;intbracketCount=0;intthisChar=0;intlastChar=0;intnextChar=0;
thisChar=fr.read();if(thisChar!=-1) {
nextChar=fr.read();
}while(thisChar!=-1) {//find and replaceswitch(thisChar) {//2. add after ";" (Except "for", and ";" between " " which is part of a string in javascript. ) and before the next linecase';'://If the ";" is in quote or in "for", then not print " "if(quoteCount>0||sigleQuoteCount>0||forCount>0) {
fw.write(';');if(forCount>0) {
forCount--;
}//Add " " after ";"}else{
fw.write(';');if(''!=nextChar&&''!=nextChar) {
fw.write('');
fillTableChar(fw, bracketCount);
}
}break;case'{'://3. add " " and "" after "{"bracketCount++;
fw.write('{');if(''!=nextChar&&''!=nextChar) {//If the file is already formatted, don't add after {.fw.write('');
fillTableChar(fw, bracketCount);
}break;case'}'://4. add " " and "" before "}"bracketCount--;
fw.write('');
fillTableChar(fw, bracketCount);
fw.write('}');if(';'!=nextChar&&'}'!=nextChar&&''!=nextChar&&''!=nextChar) {
fw.write('');
fillTableChar(fw, bracketCount);
}break;case''':
fw.write(''');if(quoteCount==0) {//When ' is not between "", change its state.sigleQuoteCount=sigleQuoteCount==0?1:0;
}break;case'"':
fw.write('"');if(sigleQuoteCount==0) {//When ' is not between "", change its state.quoteCount=quoteCount==0?1:0;
}break;case'f'://1. add before "function"if(nextChar=='u'&&lastChar!='=') {//TODO This is a very weak way to determine whether this coming word is "function", so it is need to be fixed.fw.write('');
fw.write('');
}
fw.write('f');break;default:
fw.write(thisChar);break;
}if(isAlpha(thisChar)) {if(!isAlpha(lastChar)) {
lastWord="";
}
lastWord+=String.valueOf(thisChar);
}else{if(isAlpha(lastChar)) {if("102111114".equals(lastWord)) {//"for"forCount=2;
}//TODO Whether is is suitable here to determine "function" and add " " before it?}else{
lastWord=String.valueOf(thisChar);
}
}
lastChar=thisChar;
thisChar=nextChar;if(thisChar!=-1) {
nextChar=fr.read();
}
}//close the filesfw.close();
fr.close();
}/*** Find all JS files in the specified directory.
*
*@paramdirectory The directory in which the files to be listed.
*@returnList The JS file list.*/privatestaticListgetJsFileList(String directory) {
ListjsFileList=newArrayList();
list(directory, jsFileList);returnjsFileList;
}/*** List all the JS files in the specified directory recursively.
*
*@parampath The path to be recursively searched for JS files.
*@paramresult The path and file list*/privatestaticvoidlist(String path, Listresult) {
File f=newFile(path);if(f.isDirectory()) {
File[] fileList=f.listFiles();for(inti=0; i
list(fileList[i].getPath(), result);
}
}else{if(isJsFile(f.getName())) {
result.add(f.getPath());
}
}
}/*** Determine whether the the specified file is a JS file.
*
*@paramfileName
*@returnTrue: is a JS file; False: not a JS file.*/privatestaticbooleanisJsFile(String fileName) {//TODO use pattern!!!return".js".equals(fileName.substring(fileName.length()-3));
}/*** List all JS files in the specified directory(Not in their sub-directory).
*
*@paramdir The specified directory.
*@returnString[] The JS file list.*/privatestaticString[] getSingleDirJsFileList(finalString dir) {
String[] jsFileList;
File path=newFile(dir);
jsFileList=path.list(newFilenameFilter() {privatePattern pattern=Pattern.compile(".js");publicbooleanaccept(File dir, String name) {returnpattern.matcher(newFile(name).getName()).matches();
}
});returnjsFileList;
}/*** Check whether the character is an alpha char.
* Actually, the words exist in a function name would not be limit among those we list below.
* This need to be fixed.
*
*@paramc The char to be checked.
*@returnboolean True: is alpha char; False: is not alpha char.*/privatestaticbooleanisAlpha(intc) {return((c>'a'&&c'A'&&c'0'&&c
}/*** Fill specified number of ''
*
*@paramfw FileWriter
*@paramcharNum Specified number of ''
*@throwsIOException Exception when writing file*/privatestaticvoidfillTableChar(FileWriter fw,intcharNum)throwsIOException {for(inti=0; i
fw.write('');
}
}
}