babel有可能解析JSX注释吗



问题

我正在编写一个babel插件,它在编译时修改一些JSX代码。

<MyComponent >
{/* comment here */}
</MyComponent>

我想让它读取一些本地配置并注入一些代码。我的目标是:

import Something from '/Absolute/path/to/local/config';
// component here:
<MyComponent >
<SomeHighlyConfigDependentComponent {...withConfiguredProps} />
</MyComponent>

其他一切都很好,但我实际上无法得到JSX的评论。在AST浏览器上,AST显示为:

{
"type": "JSXExpressionContainer",
"start": 82,
"end": 102,
"expression": {
"type": "JSXEmptyExpression",
"start": 83,
"end": 101
}
},

但这并没有给我太多关于以下事实的信息:

  • 这是一条评论
  • 该注释的内容等于comment here

因此,我无法可靠地将此注释("请注入"(与其他任何注释区分开来。

请不要质疑why我在做这件事;上面的伪代码是一个非常非常小的、脱离上下文的概念,它是我项目中更大事情的一部分。如果你有更好的设计方案或想法,请随时发表评论!

问题

巴别尔有什么办法";"检测";是否存在JSX评论并解析其内容?如果没有,你能解释一下原因吗?如果没有,有没有任何轻量级的替代方案可以让我在编译时做到这一点(除了暴力解析regex,这是绝对的NO(?

我尝试过的替代方案

根据这个问题,我尝试过这个:

<MyComponent >
{ null /* comment here */}
</MyComponent>

AST explorer将其解析为

{
"type": "JSXExpressionContainer",
"start": 82,
"end": 107,
"expression": {
"type": "Literal",
"start": 83,
"end": 87,
"value": null,
"raw": "null"
}
},

并不能解决问题。无法解析评论,我尝试过这个:

<MyComponent >
<div data-inject-code="SOME_CONSTANT" />
</MyComponent >

这是可行的,但它并不是非常理想,因为我们必须记录这个div是如何不出现在DOM树中的,它被替换了,而那些真正想要在修改后的代码周围使用包装器div的人可能会对这种行为感到困惑。想象一下,对<div data-inject-code="SOME_CONSTANT" className="flex flex-row" />进行编码,发现它们的flexbox包装器已经消失。

如果其他一切都失败了,我将使用这个解决方案。但是,你能理解我在这里说的吗;为什么;问题背后。babel是如何处理JSX注释的,我可以让它解析它们吗?

是的,这是可能的。问题是我在AST资源管理器中使用默认解析器acorn查看AST。根据这个问题@babel/parser是Acorn的一个分支,但它已经被完全重写了"一个主要区别是它们有不同的AST格式。将解析器切换到@babel/parser,我们将看到babel如何解析AST树的正确表示。此外,根据这个问题,acorn在其AST中不包含注释,但@babel/parser包含。

Acorn返回的语法树中不包括注释。你可以使用onComment选项来获取文件中评论的信息,但Acorn不会为你把它们放在树中(因为没有明确的方法(

<MyComponent >
{/* comment */}
</MyComponent>

这被解析为JSXExpressionContainerexpression值为:

"expression": {
"type": "JSXEmptyExpression",
"start": 84,
"end": 97,
"loc": {
"start": {
"line": 6,
"column": 5
},
"end": {
"line": 6,
"column": 18
}
},
"innerComments": [
{
"type": "CommentBlock",
"value": " comment ",
"start": 84,
"end": 97,
"loc": {
"start": {
"line": 6,
"column": 5
},
"end": {
"line": 6,
"column": 18
}
}
}
]
}

注释可以标记为内部、前导或尾部,具体取决于它们在表达式容器中的显示位置。这将解析为尾部注释:

{null /* comment */}

在这个表达式中,注释被解析为第二个数字文本的前导注释。

{1 + /* comment */ 2}

因此,我们可以这样解析JSX注释(特别是像{/* comment */}这样的注释(:

JSXExpressionContainer: {
enter(path) {
const hasComment = path.node.expression.find(expression => expression.type === 'CommentBlock' && expression.value.trim() === 'some value');
},
}

以下是babel如何解析评论的详细解释:https://github.com/babel/babel/blob/main/packages/babel-parser/ast/comment-attachment.md

  • 我们在packages/babel-parser/src/tokenizer/index.jsTokenizer#skipSpace中构造注释空白,退出跳过循环后,我们收集注释,标记位置信息并推送到parser.state.commentStack
  • 对于从parser#finishNode调用的每个已完成的AST节点。然后我们反向迭代state.commentStack。当comment.end=node.start时,我们标记trailingNode,当未定义containingNode时,标记containingNode,所以这里的第一个finishNode((是赢家,它正是我们可以附加到注释的最里面的包含节点
  • 在我们设置了包含节点之后,我们可以为相关节点分配注释。然后,解析器附加注释并进行尾部逗号调整

相关内容

  • 没有找到相关文章

最新更新