用JAVA写了一个简单的JS代码格式化工具

介绍了一个用Java编写的JS代码格式化工具,该工具能够自动为压缩格式的JS代码添加必要的换行和缩进,支持单个文件及目录内所有JS文件的批量格式化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Section I: 为什么写这个小玩意
1. 手上有些JS代码,因为某种原因,起代码中没有任何回车、制表符。在编辑器中打开时,显示的就是一行。而我实现想研究和学习这些写得比较漂亮的JS代码,
2. 可是好想没有哪个编辑器自带了JS格式化的功能。它们都可以给JS着色,但就是不能控制代码格式,真是遗憾。
3. 我是我去网上搜看有没有前人做过这个东东,发现有个JS写的JS代码格式化工具,相当不错,可以给代码格式化,还可以着色。只不过结果都是显示在网页上,复制下来的时候那些制表符都没有了,所以贴到编辑器中时,代码还是比较混乱;而且这个每次只能格式话一个文件,还得自己手动去Copy & paste;而且因为是JS写的,速度也受到了不小的限制;
基于以上原因,我准备自己些一个小工具来格式化我需要的代码:

Section II: 功能
1. 因为很多编辑器都有JS的着色功能,所一我需要的仅仅是一个格式化功能而已,那就是主要将那种故意将代码中的空白符去掉的的JS加上换行、制表符等等。
大概有一下几种情况:
  1). add /n/n before "function";
  2). add /n after ";" (Except "for", and ";" between " " which is part of a string in javascript. ) and /t before the next line;
  3). add "/n" and "/t" after "{";
  4). add "/n" and "/t" before "}".
2. 不仅可以格式话一个给定的文件,还可以格式化给定的一个文件夹里的所有的JS文件。这个就是通过传给Main函数的参数来实现的。参数可以如下:
  1)格式化一个文件:
    -f path/file.js 
  或者:
    --file path/file.js
  2) 格式化给定的一个文件夹里的所有的JS文件
    -d path/directory
  或者:
    --directory path/directory

举例:要格式化/home/newweapon/js/ 这个文件夹中的所有JS文件,可一使用如下命令:
 JsFormatter -d /home/newweapon/js

Section III 缺陷
目前写的这个程序还是一个比较脆弱的程序。有很多情况没有考虑到,我在注释中把我想到的需要提高的基本都提了一下。但是因为我写这个小玩意主要是想把我自己下的一些JS代码格式化一下,而这个对我来说已经够用了,再加上自己的水平有限,所以没有将它写得很完美。等以后有时间了,再对这个程序做一些更新。

Section IV 代码
/**
 * 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/>
 
*/
public class JsFormatter {
    
    
/* ============ constants begin =================== */
    
/** Usage */
    
public static String USAGE = "Usage:  JsFormatter -d path/directory  JsFormatter -f path/filename.js";
    
    
/** Type: Directory = "0"; File = "1" */
    
public interface Type {
        
/** Directory: 0 */
        
public static String DIRECTORY = "0";
        
/** File: 1 */
        
public static String FILE = "1";
    }
    
/* ============ constants end =================== */
    
    
/**
     * Entry point of the project.
     * 
     * 
@param args Like "-d /path/directory" or "-f /path/file.js"
     
*/
    
public static void 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;
        } 
else if("-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.
     
*/
    
private static void 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 replace
            switch(thisChar) {
            
// 2. add   after ";" (Except "for", and ";" between " " which is part of a string in javascript. ) and   before the next line
                case ';':
                    
// 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.
     
*/
    
private static 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
     
*/
    
private static void 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.
     
*/
    
private static boolean 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.
     
*/
    
private static String[] getSingleDirJsFileList(final String dir) {
        String[] jsFileList;
        File path 
= new File(dir);
        jsFileList 
= path.list(new FilenameFilter() {
            
private Pattern pattern = Pattern.compile(".js");
            
public boolean 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.
     
*/
    
private static boolean 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
     
*/
    
private static void fillTableChar(FileWriter fw, int charNum) throws IOException {
        
for(int i = 0; i < charNum; i++) {
            fw.write(
' ');
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值