用JAVA寫了一個簡單的JS程式碼格式化工具
阿新 • • 發佈:2019-01-11
/**
* cn.newweapon.JsFormatter
*/package cn.newweapon;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
/**
* @author Newweapon @ ustc [Email: newweapon111 (at) gmail.com]
* @version 0.0.1
* @Created 20071015
*
* @TODO 1. user can specify the formatted file name;<br/>
* 2. User can located the formatted files to a specified folder.<br/>
* 3. If a file is formatted partly already. Delete all blank characters first, and then format the file.<br/>
*/publicclass JsFormatter {
/* ============ constants begin =================== *//** Usage */publicstatic String USAGE ="Usage: JsFormatter -d path/directory JsFormatter -f path/filename.js";
/** Type: Directory = "0"; File = "1" */publicinterface Type {
/** Directory: 0 */publicstatic String DIRECTORY ="0";
/** File: 1 */publicstatic String FILE ="1";
}
/* ============ constants end =================== *//**
* Entry point of the project.
*
* @param args Like "-d /path/directory" or "-f /path/file.js"
*/publicstaticvoid main(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 type if(Type.FILE.equals(type)) {
if(path.length() <=3||!isJsFile(path)) {
System.err.println("The file must be a JS file.");
return;
}
}
// Start message System.out.println(startMsg);
// Format file(s)try {
if(Type.FILE.equals(type)) {
formatFile(path);
} else {
List<String> jsFileList = getJsFileList(path);
Iterator<String> it = jsFileList.iterator();
while(it.hasNext()) {
formatFile(it.next());
}
finishMsg +=" ("+ jsFileList.size() +" file(s) formatted)";
}
} catch (Exception e) {
e.printStackTrace();
return;
}
// Finish message System.out.println(finishMsg);
}
/**
* Format a JS file.
*
* @param fileName The file name of the file which is to be formatted.
* @return String The formatted string.
* @throws IOException Exception when open, read and write file.
*/privatestaticvoid formatFile(String fileName) throws IOException {
String formattedFileName = fileName +".formatted";
FileReader fr =new FileReader(fileName);
FileWriter fw =new FileWriter(formattedFileName);
String lastWord ="";
int forCount =0;
int quoteCount =0;
int sigleQuoteCount =0;
int bracketCount =0;
int thisChar =0;
int lastChar =0;
int nextChar =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 files fw.close();
fr.close();
}
/**
* Find all JS files in the specified directory.
*
* @param directory The directory in which the files to be listed.
* @return List<String> The JS file list.
*/privatestatic List<String> getJsFileList(String directory) {
List<String> jsFileList =new ArrayList<String>();
list(directory, jsFileList);
return jsFileList;
}
/**
* List all the JS files in the specified directory recursively.
*
* @param path The path to be recursively searched for JS files.
* @param result The path and file list
*/privatestaticvoid list(String path, List<String> result) {
File f =new File(path);
if(f.isDirectory()) {
File[] fileList = f.listFiles();
for(int i =0; i < fileList.length; 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.
*
* @param fileName
* @return True: is a JS file; False: not a JS file.
*/privatestaticboolean isJsFile(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).
*
* @param dir The specified directory.
* @return String[] The JS file list.
*/privatestatic String[] getSingleDirJsFileList(final String dir) {
String[] jsFileList;
File path =new File(dir);
jsFileList = path.list(new FilenameFilter() {
private Pattern pattern = Pattern.compile(".js");
publicboolean accept(File dir, String name) {
return pattern.matcher(new File(name).getName()).matches();
}
});
return jsFileList;
}
/**
* Check whether the character is an alpha char.
* <b><red>Actually, the words exist in a function name would not be limit among those we list below.
* This need to be fixed. </red></b>
*
* @param c The char to be checked.
* @return boolean True: is alpha char; False: is not alpha char.
*/privatestaticboolean isAlpha(int c) {
return ((c >'a'&& c <'z') || (c >'A'&& c <'Z') || (c >'0'&& c <'9'));
}
/**
* Fill specified number of ' '
*
* @param fw FileWriter
* @param charNum Specified number of ' '
* @throws IOException Exception when writing file
*/privatestaticvoid fillTableChar(FileWriter fw, int charNum) throws IOException {
for(int i =0; i < charNum; i++) {
fw.write('');
}
}
}
* cn.newweapon.JsFormatter
*/package cn.newweapon;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
/**
* @author Newweapon @ ustc [Email: newweapon111 (at) gmail.com]
*
* @Created 20071015
*
* @TODO 1. user can specify the formatted file name;<br/>
* 2. User can located the formatted files to a specified folder.<br/>
* 3. If a file is formatted partly already. Delete all blank characters first, and then format the file.<br/>
/* ============ constants begin =================== *//** Usage */publicstatic String USAGE ="Usage: JsFormatter -d path/directory JsFormatter -f path/filename.js";
/** Type: Directory = "0"; File = "1" */publicinterface Type {
/** Directory: 0 */publicstatic String DIRECTORY
/** File: 1 */publicstatic String FILE ="1";
}
/* ============ constants end =================== *//**
* Entry point of the project.
*
* @param args Like "-d /path/directory" or "-f /path/file.js"
*/publicstaticvoid main(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 type if(Type.FILE.equals(type)) {
if(path.length() <=3||!isJsFile(path)) {
System.err.println("The file must be a JS file.");
return;
}
}
// Start message System.out.println(startMsg);
// Format file(s)try {
if(Type.FILE.equals(type)) {
formatFile(path);
} else {
List<String> jsFileList = getJsFileList(path);
Iterator<String> it = jsFileList.iterator();
while(it.hasNext()) {
formatFile(it.next());
}
finishMsg +=" ("+ jsFileList.size() +" file(s) formatted)";
}
} catch (Exception e) {
e.printStackTrace();
return;
}
// Finish message System.out.println(finishMsg);
}
/**
* Format a JS file.
*
* @param fileName The file name of the file which is to be formatted.
* @return String The formatted string.
* @throws IOException Exception when open, read and write file.
*/privatestaticvoid formatFile(String fileName) throws IOException {
String formattedFileName = fileName +".formatted";
FileReader fr =new FileReader(fileName);
FileWriter fw =new FileWriter(formattedFileName);
String lastWord ="";
int forCount =0;
int quoteCount =0;
int sigleQuoteCount =0;
int bracketCount =0;
int thisChar =0;
int lastChar =0;
int nextChar =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 files fw.close();
fr.close();
}
/**
* Find all JS files in the specified directory.
*
* @param directory The directory in which the files to be listed.
* @return List<String> The JS file list.
*/privatestatic List<String> getJsFileList(String directory) {
List<String> jsFileList =new ArrayList<String>();
list(directory, jsFileList);
return jsFileList;
}
/**
* List all the JS files in the specified directory recursively.
*
* @param path The path to be recursively searched for JS files.
* @param result The path and file list
*/privatestaticvoid list(String path, List<String> result) {
File f =new File(path);
if(f.isDirectory()) {
File[] fileList = f.listFiles();
for(int i =0; i < fileList.length; 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.
*
* @param fileName
* @return True: is a JS file; False: not a JS file.
*/privatestaticboolean isJsFile(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).
*
* @param dir The specified directory.
* @return String[] The JS file list.
*/privatestatic String[] getSingleDirJsFileList(final String dir) {
String[] jsFileList;
File path =new File(dir);
jsFileList = path.list(new FilenameFilter() {
private Pattern pattern = Pattern.compile(".js");
publicboolean accept(File dir, String name) {
return pattern.matcher(new File(name).getName()).matches();
}
});
return jsFileList;
}
/**
* Check whether the character is an alpha char.
* <b><red>Actually, the words exist in a function name would not be limit among those we list below.
* This need to be fixed. </red></b>
*
* @param c The char to be checked.
* @return boolean True: is alpha char; False: is not alpha char.
*/privatestaticboolean isAlpha(int c) {
return ((c >'a'&& c <'z') || (c >'A'&& c <'Z') || (c >'0'&& c <'9'));
}
/**
* Fill specified number of ' '
*
* @param fw FileWriter
* @param charNum Specified number of ' '
* @throws IOException Exception when writing file
*/privatestaticvoid fillTableChar(FileWriter fw, int charNum) throws IOException {
for(int i =0; i < charNum; i++) {
fw.write('');
}
}
}