什么是MagicString,这些行是如此神奇吗?

MagicString是一个鲜为人知的库。尽管如此,它还是解决了最紧迫的问题之一-使用其结构(AST-抽象语法树)更改源代码。

在本文中,我们将学习什么是MagicString以及这些行是否真的“神奇”。这将帮助我们理解下一篇文章,其中我将解释我们如何如此快速地翻译Angular文档,以及如何为Markdown和任何其他格式的文件创建通用翻译器。





2周前,我发布了Angular的俄语文档(angular24.ru)。在此期间,添加了35个问题,并在文本中进行了更正,并添加了2个请求。我衷心怀疑您选择文本,提供翻译并自动在GitHub上发布的系统是否可以正常工作。但是众包有效! :)您可以从本文中了解更多信息

发布后,最常见的问题之一是:“为什么?”。这个问题是绝对正确的,但是要回答这个问题,您首先必须了解MagicString是什么,它如何工作以及如何有用。

假设我们有一个简单的源代码:

const a = 1;

我们想var代替const。最简单的解决方案是用通常的String.prototype.replace将const替换为var 。对于此任务,这很可能是最正确的解决方案。但是,如果仅在全局范围内需要用var替换const怎么办?但是,不要在函数内部替换它们吗?当然,您可以提出更复杂的规律性或编写棘手的代码,但是有更可扩展和灵活的方式。 我们可以使用解析器来获取AST-抽象语法树。如果您对AST是什么感兴趣,请访问astexplorer.net。本质上,它是一棵树,可以准确显示您的代码结构。 此外,此AST中的每个节点都有一个起点



结束指示在源代码中这些元件的位置的索引。知道了这些坐标并掌握了文件的结构之后,我们就可以在保留文件结构的情况下进行复杂的替换和排列。



通常,替换是使用访问者模式设计和几个帮助程序完成的,这些帮助程序通常将自己包装在一个库中,该库可以称为“变压器API”。每个解析器都有自己的“转换器API”。

这样的库非常易于使用,但是存在一些问题。其中之一就是性能。

由于AST树中的每个节点(几乎每个节点)都包含坐标,因此当更改1个节点时,我们经常需要更新其余树的坐标。在这里,您可以辩解说,您可以花一点点钱做-不要在任何地方更新坐标,而只需根据结构将AST渲染回文本即可。但是有一个问题:您将立即失去原始文本的格式,这与我们的任务相矛盾-在现有行中用var替换const。实际上,我们得到了具有新格式的新行。并且,如果这对于一小行来说不是问题,那么想象一下一个1000行的文件,由于将const替换var,因此其格式已完全更改。听起来不是很好。



这就是MagicString的魔力。我首先从Rich Harris项目(即胡桃木)中得知它们的存在。胡桃木是JavaScript的缩小器。据称Butternutt比UglifyJS快3倍比Babili快10-15倍。我先说,至少3年前,该项目被一个铜盆覆盖。但是即使那样,我仍然对其表现的秘密着迷。这是一个MagicString。

让我们看一下使用MagicString的方法:

var MagicString = require( 'magic-string' );
var s = new MagicString( 'const a = 1; const b = 2;' );

s.overwrite( 0, 5, 'var' );
s.toString(); // 'var a = 1; const b = 2;'

//  

MagicString的算法非常简单:我们将原始字符串包装在一个对象中,在该对象中我们不直接将更改应用于该字符串,而是将坐标和将来需要做的事情添加到数组中。而且只有当有人想要获得结果行时,我们才从1到1开始执行累积的操作。例如:

  1. 我们用var替换了const,从索引0开始到索引5结束
  2. 我们知道,所有后续替换都必须具有小于2的索引(var比const小2个字符,短一行)
  3. 我们更新所有操作的坐标
  4. 我们应用以下操作,等等。




一切看起来都很简单。但是为什么MagicString更快呢?答案很简单:我们在树上执行的操作数量远少于AST节点的数量。更不用说AST所需的内存量以及“树遍历(遍历树)不是自由操作”这一事实,而是O(n + m)



如果我准备再等半个小时?这是MagicString的第二个优点。每个解析器发明自己的API进行转换。而且,这仍然非常好,如果有这样的API(并非每个解析器都提供),通常我们将无法使用AST替换源文本。但是MagicString是用于更改源字符串的单个通用API。使用哪个解析器或解析器的组合都没有关系。使用MagicString,您可以与任何AST一样出色地工作。



希望您对MagicString感兴趣。在下一篇文章中,我将讨论双MagicString以及如何制作Markdown文档的通用翻译器。

订阅我的电报频道@obenjiro_notes和Twitter obenjiro以免错过有关该主题的以下文章以及许多其他有趣的事情。

All Articles