作为前端,我们将使用许多编译工具:打字稿编译器,Babel,Eslint,Postcss等。其AST的AST不同,但是只有一个AST遍历算法。我们不相信。
编译工具将将源代码转换为AST,从而将字符串的操作转换为AST对象树的操作。
由于您想操作AST,因此您需要找到需要遍历的相应AST。
如何穿越?
AST不是一棵树,并且首选和优先考虑树的遍历,这里只能是最优先的。
那么您如何穿越每个AST呢?
例如,这种二进制表达需要穿越左右属性
例如,此IFStatement需要穿越测试,Reactece属性:
通过这种方式,我们记录了如何遍历每个AST,然后记录了根节点的穿越。
这样的人:
因为每个AST访问这些键,所以称为VisitorKeys。
当您遍历每个AST时,请从VisitorKeys中查找它,以查看要遍历哪些属性,然后取出递归遍历。
这是AST的遍历过程,只有这样的过程。(您还能想到第二种吗?)
当然,尽管只有一个想法,但仍然存在一些变形:
例如,将递归变成一个周期,因为如果AST太深,递归水平太深,并且可能会溢出,因此您可以添加一个数组(作为堆栈)来记录下一个遍历,以便它可以变成一个周期。(反应纤维也使递归周期变成)
例如,您无法提出访问者,而是直接写入代码。尽管更容易扩展,但对某些AST进行一些逻辑更改更为方便。
说了很多话,但是您可能不相信,然后我们将查看源代码,以查看Babel,Eslint,TSC,Estraverse,Postcss如何遍历AST。
源代码中有很多无关的信息,我们专注于遍历部分:
Eslint的遍历过程相对标准,让我们首先看一下:
它是从每个AST中的visitorkeys遍历的属性键,然后递归遍历每个密钥的值。如果数组是数组,则必须将其穿过每个元素。
就像上面清除的想法一样。
此外,您可以在Traversal之前调用Enter回调功能,并且可以在Traversal后调用出口回调功能。
巴别尔也是同一想法。您可以通过VisitorKeys记录每个AST,然后在浏览递归访问时取出相应的密钥:
Babel分为两种方法,没有实质性的差异,并且有两个阶段的Enter和退出阶段。
estraverse是一个用于遍历AST的库,通常与Esprima的解析器匹配。AST遍历与上面的两个不同,只是将递归变成一个循环。
看到我标记的地方,它与上面相同,但在这里不是递归,而是将AST传播到阵列中,然后继续循环。
这是递归更改周期的想法,只需添加一个数组(作为堆栈)记录路径。
打字稿的遍历与上面的遍历不同。它没有从VisitorKeys中汲取数据,而是写了哪些属性要在代码中访问:
此方法比较命令公式。所有AST都必须再次列举,并且在上面撤出Visitorkeys的方法是陈述。逻辑可以重复使用。我不知道为什么ts写下这样的逻辑。好处可能是您可以修改一些遍历逻辑。
PostCSS也有些不同。它的所有钥匙都是遍历的,不需要游客,只能穿越所有钥匙。
PostCSS的节点可以通过面向对象的方式组织遍历。
写作有些不同,但是遍历的思想没有改变。
前端字段中有很多编译工具。它们基于AST,AST的操作需要穿越才能找到它。
ESLINT,BABEL,ESTRAVERSE,POSTCSS,打字稿编译器和其他编译器通过AST的实现进行遍历。在代码中,思维是相同的。
因此,让我们正式得出结论: