使用JavaScript自定义规则进行静态分析?

时间:2012-08-05 13:12:00

标签: javascript code-analysis jslint jshint

JSLint,JSHint或其他一些开源静态代码分析工具是否支持为代码合规性添加自定义规则,或者是否有一些符合ECMAScript的解析器可用于使结果尽可能接近于下面的片段?

例如,我想查看JavaScript代码并列出调用哪些函数,如果它调用库(或智能手机为HTML5小部件提供的API)来注册属于该API命名空间的所有内容,创建一个对象树及其属性,以查看函数是否可以追溯到哪个对象,可能是XML,JSON或其他结构化格式的输出。

比如说我有这个JavaScript代码(它什么也没做,只是为了参数):

jobs = mylibrary.getJobs();
found = jobs.find("Python");
list = found.convert("html");

我希望我的分析工具能够实现这个目标:

{
    "mylibrary": {
        "jobs": {"maker":"getJobs", "parent": "mylibrary"},
        "found": {"maker": "find", "parent": "jobs", "parameters": "Python"},
        "list": {"maker": "convert", "parent": "found"}
    }
}

3 个答案:

答案 0 :(得分:2)

你应该能够使用suback的burrito来构建这样的东西,它使用来自Uglify-JS的解析器,并且我认为你提供了所需的一切。快速示例:

src.js:

var jobs, found, list;
jobs = mylibrary.getJobs();
found = jobs.find("Python");
list = found.convert("html");

ast.js:

var fs = require('fs'),
    burrito = require('burrito');

var src = fs.readFileSync('./src.js', 'utf8');

burrito(src, function (node) {
    console.log(node.name, node.value);
});

你究竟如何建立你所要求的结构,我不太确定(我对自己的AST解析不太熟悉)但我相信你需要付出一些努力。也许您不需要介于两者之间的结构,可以这么说,但可以只从burrito验证每个节点,其中每个call节点将根据其值(函数名称,对象名称等)进行验证,如果没有验证则会发出警告。

以上是上面burrito调用的输出(注意:每个[Object]或者此类节点已被node.js'console.log截断。值实际上是解析树中的节点burrito,所以每个值都有它的关联状态等。)

var [ [ [ 'jobs' ], [ 'found' ], [ 'list' ] ] ]
stat [ [ { name: 'assign', start: [Object], end: [Object] },
    true,
    [ [Object], 'jobs' ],
    [ [Object], [Object], [] ] ] ]
assign [ true,
  [ { name: 'name', start: [Object], end: [Object] }, 'jobs' ],
  [ { name: 'call', start: [Object], end: [Object] },
    [ 'dot', [Object], 'getJobs' ],
    [] ] ]
name [ 'jobs' ]
call [ [ 'dot', [ 'name', 'mylibrary' ], 'getJobs' ], [] ]
stat [ [ { name: 'assign', start: [Object], end: [Object] },
    true,
    [ [Object], 'found' ],
    [ [Object], [Object], [Object] ] ] ]
assign [ true,
  [ { name: 'name', start: [Object], end: [Object] }, 'found' ],
  [ { name: 'call', start: [Object], end: [Object] },
    [ 'dot', [Object], 'find' ],
    [ [Object] ] ] ]
name [ 'found' ]
call [ [ 'dot', [ 'name', 'jobs' ], 'find' ],
  [ [ [Object], 'Python' ] ] ]
string [ 'Python' ]
stat [ [ { name: 'assign', start: [Object], end: [Object] },
    true,
    [ [Object], 'list' ],
    [ [Object], [Object], [Object] ] ] ]
assign [ true,
  [ { name: 'name', start: [Object], end: [Object] }, 'list' ],
  [ { name: 'call', start: [Object], end: [Object] },
    [ 'dot', [Object], 'convert' ],
    [ [Object] ] ] ]
name [ 'list' ]
call [ [ 'dot', [ 'name', 'found' ], 'convert' ],
  [ [ [Object], 'html' ] ] ]
string [ 'html' ]

<强>更新

另一种选择是较新的(?)ES解析器Esprima,它似乎更积极地开发并且更好地记录。据报道,它也比Uglify更快。你可以尝试例如解析Parsing Demo page。你可以用这个方法建立一个好的解决方案。

答案 1 :(得分:1)

我尝试了一些可以从代码访问的javascript解释器(在我的例子中是python)。因此,pynocerospynarcissuspyv8等口译员可能对我有帮助。

这里有一个关于如何安装py8:https://stackoverflow.com/a/11879224/1577343

的答案

由于采用上述方法,我没有取得多大成功,我更喜欢使用符合ECMAScript的解析器的静态分析解决方案。

使用静态分析,我可以得到的是使用JSLINT解析器(Run JSLint on a .js file from debugging console in chrome or firefox): 但我不知道如何进一步使用它。

{
    "string": "(begin)",
    "first": [
        {
            "string": "var",
            "arity": "statement",
            "first": [
                {
                    "string": "jobs"
                },
                {
                    "string": "found"
                },
                {
                    "string": "list"
                }
            ]
        },
        {
            "string": "=",
            "arity": "infix",
            "first": {
                "string": "jobs"
            },
            "second": {
                "string": "(",
                "arity": "infix",
                "first": {
                    "string": ".",
                    "arity": "infix",
                    "first": {
                        "string": "mylibrary"
                    },
                    "second": {
                        "string": "getJobs"
                    }
                },
                "second": []
            }
        },
        {
            "string": "=",
            "arity": "infix",
            "first": {
                "string": "found"
            },
            "second": {
                "string": "(",
                "arity": "infix",
                "first": {
                    "string": ".",
                    "arity": "infix",
                    "first": {
                        "string": "jobs"
                    },
                    "second": {
                        "string": "find"
                    }
                },
                "second": [
                    {
                        "string": "Python",
                        "arity": "string"
                    }
                ]
            }
        },
        {
            "string": "=",
            "arity": "infix",
            "first": {
                "string": "list"
            },
            "second": {
                "string": "(",
                "arity": "infix",
                "first": {
                    "string": ".",
                    "arity": "infix",
                    "first": {
                        "string": "found"
                    },
                    "second": {
                        "string": "convert"
                    }
                },
                "second": [
                    {
                        "string": "html",
                        "arity": "string"
                    }
                ]
            }
        }
    ]
}

答案 2 :(得分:1)

PMD支持使用自定义规则进行ECMAScript静态分析:

  

使用当前规则集之一作为示例。将其复制并粘贴到新文件中,从中删除所有旧规则,然后更改名称和说明。

     

请注意,您可以自定义单个引用的规则。除了规则类之外的所有内容都可以在自定义规则集中覆盖。

     

您还可以使用排除模式排除规则集处理某些文件,并使用可选的覆盖包含模式。当存在匹配的排除模式但是没有匹配的包含模式时,将从处理中排除文件。

     

源文件路径中的路径分隔符被规范化为&#39; /&#39;字符,因此可以透明地在多个平台上使用相同的规则集。

     

此外,无论PMD如何使用(例如命令行,IDE,Ant),此排除/包含技术都能正常工作,从而可以更轻松地在整个环境中保持PMD规则的应用一致。

     

您可以指定自定义规则集名称的完整路径以及内置PMD规则集

     

要在IDE中查看它,请将其添加到rulesets / rulesets.properties

<强>参考