与 Prettier 的区别
在某些情况下,Biome 主观决定以与 Prettier 输出不一致的方式来格式化代码。下文将解释这些差异。
Prettier 不会取消引用某些作为有效 JavaScript 标识符的对象属性
Section titled Prettier 不会取消引用某些作为有效 JavaScript 标识符的对象属性Prettier 和 Biome 取消引用作为有效 JavaScript 标识符的对象和类属性。 Prettier 仅取消引号有效的 ES5 标识符.
这是 ES2015 现在广泛使用的生态系统中的遗留限制。 因此,我们决定通过在 ES2015+ 中取消引用所有有效的 JavaScript 标识符来实现不同。
一个可行的解决方法是引入一个配置来设置项目使用的 ECMAScript 版本。
然后我们可以根据该版本调整取消引用行为。
将 ECMAScript 版本设为 ES5
可以匹配 Prettier 的行为。
区别
Prettier 在计算键中的赋值行为不一致
Section titled Prettier 在计算键中的赋值行为不一致Prettier 和 Biome 将一些赋值表达式括在括号之间,特别是在条件语句中。 这使得 Biome 能够识别应该进行比较的表达。
Prettier 的行为并不一致,因为它在对象属性的计算键赋值时添加括号,而在类属性的计算键赋值时不添加括号,如下例所示:
输入
区别
为了保持一致,我们决定舍弃括号。 或者,我们也可以把任何赋值括在对象或类的计算键中。
Prettier 为箭头函数的类型参数添加了逗号尾部,即使在不需要逗号尾部的情况下也是如此
Section titled Prettier 为箭头函数的类型参数添加了逗号尾部,即使在不需要逗号尾部的情况下也是如此在某些特定情况下,箭头函数的类型参数列表需要使用逗号来与 JSX 元素区分开来。 如果提供了默认类型,则不需要使用逗号。 在这里,我们偏离了 Prettier,因为我们认为这样更能尊重 Prettier 的初衷,即只有在需要时才添加尾部逗号。
输入
区别
Prettier 对括号中的非空断言可选链的行为不一致
Section titled Prettier 对括号中的非空断言可选链的行为不一致在 TypeScript 中,非空断言操作符 !
允许断言一个值是非空的。
当应用于可选链时,断言适用于整个链,无论是否存在括号,
使 (a.?.b)!
和 a.?.b!
等同。
根据 Prettier,前面的代码示例已经格式化得很好了。 Prettier 用于强制括号的存在或不存在。 这看起来像是错失了标准化代码的机会。
此外,即使括号包含了非空断言,Prettier 也不会移除括号。 相反,它会将运算符移到括号外。
输入
区别
Prettier 格式化无效语法
Section titled Prettier 格式化无效语法Prettier 对 JavaScript 和 TypeScript 的基于 Babel 的解析非常宽松,允许忽略多个错误。 Biome 的解析器有意比 Prettier 解析器更严格。 它能正确识别以下语法错误:
- 函数不能有重复的修改器
- 属性修饰符的顺序无效
- 函数声明不允许有主体
- 非抽象类不能有抽象属性
- 不能指定可选链
- 不能在接口的类型参数上设置
const
修饰符 - 顶层返回
- 等等…
在 Prettier 中,这些错误不被视为解析错误,AST 仍会 “正确” 地使用适当的节点构建。 在格式化时,Prettier 会将这些节点视为正常节点并进行相应格式化。
在 Biome 中,解析错误会导致 Bogus
节点,其中可能包含任意数量的有效节点、无效节点和/或原始字符。
在格式化时,Biome 会将假节点视为纯文本,将其逐字打印到生成的代码中,而不进行任何格式化,因为尝试格式化它们可能会导致错误和语义变化。
对于类属性,Prettier 当前的解析策略也使用布尔字段来表示修饰符,这意味着每种修饰符只能出现一个(可访问性修饰符存储为单个字符串)。 打印时,Prettier 会查看布尔字段列表,然后决定再次打印哪些修饰符。而 Biome 保存的是修饰符列表,这意味着重复的修饰符会被保留下来并被分析(因此会出现关于重复修饰符和排序的解析错误信息)。 在打印出假节点时,该列表将保持不变,而打印出未格式化的文本时,这些修饰符将继续存在。
Biome 有多种方法可以解决这个问题。 一种可能性是在格式化时尝试解释虚假节点并从中构造有效节点。 如果可以构建有效的节点,那么它只会像正常一样格式化该节点,否则,它会像当前一样逐字打印伪造的文本。 然而,这很混乱,并且向格式化程序引入了一种没有意义的解析逻辑形式。
另一种方法是在解析器中引入某种形式的“语法无效假节点”,它可以接受这类纯粹的语义错误(重复修饰符、非抽象类中的抽象属性)。
它将继续像正常一样构建节点(有效匹配 Prettier 中的行为),但会将节点存储在一种新的假节点中,包括诊断结果。
在格式化时,这些特定的假节点会尝试格式化内部节点,如果出现错误,就会回退(现有的 format_or_verbatim
工具已经可以做到这一点)。
这将使解析和格式化逻辑相互分离,但会给解析器带来更多复杂性,使无效状态被视为半有效状态。
类属性上的重复修饰符
Section titled 类属性上的重复修饰符输入
区别
分配给一个可选链
Section titled 分配给一个可选链输入
区别
接口类型参数的修饰符不正确
Section titled 接口类型参数的修饰符不正确输入
区别
错误的自增和自减
Section titled 错误的自增和自减输入
在非抽象类中使用 abstract
修饰符
Section titled 在非抽象类中使用 abstract 修饰符输入
区别
Prettier 在 TypeScript 和 Babel 解析之间存在不一致问题
Section titled Prettier 在 TypeScript 和 Babel 解析之间存在不一致问题Prettier 支持多种不同的 JavaScript 和 TypeScript 代码解析器,所有这些解析器都旨在与 estree
规范兼容。 大多数情况下,Prettier 使用 Babel 作为 JavaScript 代码的默认解析器,但在解析 TypeScript 时,它会首先尝试使用 TypeScript 自带的解析器,然后在启用 TypeScript 后才返回 Babel。虽然 TypeScript 解析器通常与 estree 兼容,但它并不精确,这可能会导致一些不一致,从而影响 Prettier 创建的输出。一般来说,这些被认为是 Prettier 本身的错误,因为无论使用哪个解析器,输出都应该是相同的。
Biome 实现了自己的解析,可以处理所有形式的 JavaScript 和 TypeScript 代码,这意味着两者之间不应该存在任何不一致。不过,在将 TypeScript 代码库从 Prettier 迁移到 Biome 时,可能会因为 Prettier 解析器之间的差异而导致某些格式发生变化。
这些情况在 Biome 中不被视为错误或不兼容。如果格式化的代码在使用 Prettier 中的 typescript 解析器设置时显示不同,但在使用 babel 和/或 babel-ts 时匹配,则 Biome 认为输出是兼容的。
作为一个例子,考虑这种情况,使用 Biome 和 Prettier 3.1.0 以及 typescript
解析器进行格式化:
输入
区别
使用 TypeScript 解析器的 Prettier 选择在一行上编写 isEqual
调用,而 Biome 将 Prettier 的输出与 babel
和 babel-ts
解析器进行匹配。因此,这不被视为与 Biome 不兼容,而是被视为 Prettier 中的错误。