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

4
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"}
    }
}

你的意思是像分析一样,但返回HTML5内容的XML数据吗?例如,监视所有点击HTML5音频的人,然后将该数据发送到XML数据中,以便您可以导出到图表等? - TheBlackBenzKid
@TheBlackBenzKid:我的意思是静态分析(而不是动态分析),但是针对代码(包括.js和<script>部分),例如列出所有调用的函数及其所属的库等,匿名函数,“扩展”对象等。 - Eduard Florinescu
你能否尝试使用FireBug并查看DOM视图? - TheBlackBenzKid
@TheBlackBenzKid:那仍然是动态分析,实际上我需要的是能够从JavaScript对象中生成类似DOM结构的东西(可能是XML或JSON),而不需要通过浏览器引擎运行.js文件。 谢谢你的回复,让我更清楚地知道我需要什么。 - Eduard Florinescu
抱歉,我不能提供更多的帮助。 - TheBlackBenzKid
3个回答

3

您应该能够使用substack的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更快。您可以在解析演示页面上尝试解析等操作。使用这个工具,您应该能够构建一个很好的解决方案。


谢谢,这看起来是迄今为止最有前途的,我会试着玩一下,看看我能做些什么。 - Eduard Florinescu
1
好的,请看看我的关于Esprima的注释,它似乎非常方便! - Linus Thiel
Esprima更好,你的答案是迄今为止最好的,今天我完成了投票,也想把问题保持开放状态直到赏金结束;) - Eduard Florinescu

1

我尝试了一些使用JavaScript解释器的方法,可以从代码(在我的情况下是Python)中访问。因此,像pynocerospynarcissuspyv8这样的解释器可能会对我有所帮助。

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

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

在静态分析方面,我能够做到的最远的是使用JSLINT解析器(在Chrome或Firefox的调试控制台上运行JSLint .js文件):但我不知道如何进一步使用它。

{
    "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"
                    }
                ]
            }
        }
    ]
}

1

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

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

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

您还可以使用排除模式来排除某些文件不被规则集处理,并提供可选的覆盖包含模式。当存在匹配的排除模式但没有匹配的包含模式时,文件将被排除在处理之外。

源文件路径中的路径分隔符被标准化为“/”字符,因此同一规则集可以透明地用于多个平台。

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

您可以将自定义规则集名称的完整路径指定为内置PMD规则集的一部分。

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

参考资料


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接