【问题标题】:Using google closure compiler to parse javascript source使用 google 闭包编译器解析 javascript 源代码
【发布时间】:2017-02-24 03:15:04
【问题描述】:

我想使用 google 闭包编译器解析给定的 ES6 源文件,以构建程序的自定义“面向对象”表示。这种表示将包括源文件中的所有类以及这些类中包含的方法和变量的详细信息。我已经为使用 Antlr 的 Java 程序完成了这项任务——一旦你有了合适的 grammar,你就可以为任何需要的语法规则(类声明、方法声明等)注册进入和退出监听器,这使得实施相当简单。如果能够使用 google 闭包编译器解析 JavaScript 代码以提取有关源代码的类似信息,我将不胜感激。

到目前为止,我有以下代码可以解析给定的 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 类简单地输出每个处理的节点的类型和限定名称,如下所示:

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`

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

【问题讨论】:

    标签: javascript google-closure-compiler


    【解决方案1】:

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

    【讨论】:

    • 如何判断给定节点是类名、函数名还是变量名?另外,一旦我找到了一个类名节点,我怎么知道我们什么时候完成了这个节点在语义上代表的类的解析呢?有没有我可以寻找的特殊“退出”节点,或者有其他方法可以做到这一点?
    • 您必须将 AST 视为一个整体。编译器有许多通过分析 AST 的过程,这些都是很好的例子。这是一个:github.com/google/closure-compiler/blob/master/src/com/google/…
    【解决方案2】:

    以下代码打印出给定 JavaScript 程序中的所有方法和类,并概述了使用 Google Closure-Compiler 的 Java API 分析 JavaScript 代码的基本方法,有关更多详细信息,请参阅我写的 this post

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

    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...
        }
    }
    

    接下来我们初始化一个编译器并在给定的 JavaScript 源文件上运行我们创建的 JavaScript 分析器。

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多