使用 google 闭包编译器解析 javascript 源代码

Using google closure compiler to parse javascript source

我想使用 google 闭包编译器解析给定的 ES6 源文件,以便构建程序的自定义 'object-oriented' 表示。此表示将包括 源文件中所有 classes 的详细信息以及这些 classes 中包含的方法和变量。我已经为我使用 Antlr - once you have a suitable grammar 的 Java 程序完成了这项任务,您可以为任何所需的语法规则(class 声明、方法声明等)注册进入和退出侦听器,这使得实施相当简单。如果能够使用 google 闭包编译器解析 Java 脚本代码以提取有关源代码的类似信息,我将不胜感激。

到目前为止,我有以下代码可以解析给定的 javascript 源文件:

Compiler compiler = new Compiler();
CompilerOptions options = new CompilerOptions();
options.setIdeMode(true);
compiler.initOptions(options);
Node root = new JsAst(SourceFile.fromCode(file.name(), file.content())).getAstRoot(compiler);
NodeTraversal.traverseEs6(compiler, root, new JavaScriptParsePass());

JavaScriptParsePass class 简单地输出处理的每个节点的类型和限定名称,如下所示:

public class JavaScriptParsePass extends AbstractPostOrderCallback implements CompilerPass {

    @Override
    public void process(Node externs, Node root) {
    }

    @Override
    public void visit(NodeTraversal t, Node n, Node parent) {
        System.out.println(n.getType() + ": " + n.getQualifiedName());
    }
}

运行这个程序就输入: class Model { constructor(properties) { this.properties = properties; }

产生输出:

38: Model
124: null
38: null
38: properties
83: null
42: this
40: null
33: this.properties
38: properties
86: null
130: null
125: null
105: null
160: null
159: null
158: null
132: null`

我希望能对此输出进行解释,因为排序和空值对我来说没有任何意义,以及有关如何解决原始问题的任何一般指导。

您得到的是空值,因为 n.getQualifiedName() 仅适用于名称节点。这将包括变量名称、函数名称、class 名称和属性。对于大多数 AST 节点类型,它不会打印出有意义的数据。

以下代码打印出给定 JavaScript 程序中的所有方法和 classes,并概述了使用 Google 分析 JavaScript 代码的基本方法Closure-Compiler 的 Java API,更多细节见 this post 我写的

首先,我们需要扩展 AbstractShallowCallback class,它提供了一种遍历解析树中节点的方法。我们为访问方法提供了一个实现,如果它是我们感兴趣的节点,它将输出节点的值。

public class JavaScriptAnalyzer extends AbstractShallowCallback {

@Override
    public void visit(NodeTraversal t, Node n, Node parent) {
        if (n.isClass()) {
            System.out.println(n.getFirstChild().getString());
        }
        if (n.isMemberFunctionDef() || n.isGetterDef() || n.isSetterDef()) {
            System.out.println(n.getString());
        }
        if (n.isFunction()) {
            System.out.println(n.getFirstChild().getString());
        }
        // there is more work required to detect all types of methods that
        // has been left out for brevity...
    }
}

接下来我们初始化编译器和 运行 我们在给定的 Java 脚本源文件上创建的 Java 脚本分析器。

public void parse(String jsFileContent, String jsName) throws Exception {
    Compiler compiler = new Compiler();
    CompilerOptions options = new CompilerOptions();
    options.setIdeMode(true);
    compiler.initOptions(options);
    Node root = new JsAst(SourceFile.fromCode(jsName, jsFileContent)).getAstRoot(compiler);
    JavaScriptAnalyzer jsListener = new JavaScriptAnalyzer();
    NodeTraversal.traverseEs6(compiler, root, jsListener);
}

运行 上面的代码在下面的源文件中:

class Polygon {
   constructor(height, width) {}
   logWidth() {}
   set width(value) {}
   get height(value) {}
}

按预期生成以下输出:

constructor
logWidth
width
height
Polygon