【问题标题】:Static-analysis with custom rules for JavaScript?使用 JavaScript 自定义规则进行静态分析?
【发布时间】:2023-04-02 02:41:01
【问题描述】:

JSLint、JSHint 或其他一些开源静态代码分析工具是否支持为代码合规性添加自定义规则,或者是否有一些符合 ECMAScript 的解析器可以用来获得尽可能接近于下面的sn-p?

例如,我想查看 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:我的意思是静态分析(不是动态分析),而是代码(.js 和
  • 你不能试试 FireBug 并查看 DOM 视图吗?
  • @TheBlackBenzKid:那仍然是动态分析,实际上我需要的是生成类似 DOM 的结构(可能是 XML 或 Jason)但仅来自 javascript 对象而不运行.js 通过浏览器引擎。感谢您的回复,这让我更清楚我需要什么。
  • 抱歉,我无法提供更多帮助。

标签: javascript code-analysis jslint jshint


【解决方案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】:

    您应该能够使用 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 解析不是很精通),但我相信这需要您付出一些努力。也许您不需要中间的结构,可以这么说,但可以只验证墨西哥卷饼中的每个节点,其中每个 call 节点将根据其值(函数名称、对象名称等)进行验证,并发出警告如果它没有验证。

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

    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。我认为,您应该能够使用它构建一个好的解决方案。

    【讨论】:

    • 谢谢,这看起来是迄今为止最有希望的,我会玩弄它,看看我能完成什么。
    • 听起来不错——也请参阅我关于 Esprima 的说明——它确实看起来很方便!
    • Esprima 更好,到目前为止你的回答是最好的,因为今天我完成了投票,而且我想把问题留到赏金结束;)
    【解决方案3】:

    PMD 支持带有自定义规则的 ECMAScript 静态分析:

    以当前规则集之一为例。将其复制并粘贴到您的新文件中,从中删除所有旧规则,然后更改名称和描述。

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

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

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

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

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

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

    参考文献

    【讨论】:

      猜你喜欢
      • 2017-10-29
      • 2014-05-30
      • 2011-01-10
      • 2012-08-01
      • 1970-01-01
      • 2011-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多