biome-developer
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePurpose
目的
This skill provides general development best practices, common gotchas, and Biome-specific patterns that apply across different areas of the codebase. Use this as a reference when you encounter unfamiliar APIs or need to avoid common mistakes.
本技能提供适用于代码库不同领域的Biome通用开发最佳实践、常见陷阱及专属模式。当你遇到不熟悉的API或需要规避常见错误时,可将其作为参考。
Prerequisites
前置要求
- Basic familiarity with Rust
- Understanding of Biome's architecture (parser, analyzer, formatter)
- Development environment set up (see CONTRIBUTING.md)
- 基本熟悉Rust
- 了解Biome的架构(解析器、分析器、格式化器)
- 已搭建开发环境(详见CONTRIBUTING.md)
Common Gotchas and Best Practices
常见陷阱与最佳实践
Working with AST and Syntax Nodes
处理AST与语法节点
DO:
- ✅ Use parser crate's to inspect AST structure before implementing
quick_test - ✅ Understand the node hierarchy and parent-child relationships
- ✅ Check both general cases AND specific types (e.g., Vue has both and
VueDirective)VueV*ShorthandDirective - ✅ Verify your solution works for all relevant variant types, not just the first one you find
DON'T:
- ❌ Build the full Biome binary just to inspect syntax (expensive) - use parser crate's instead
quick_test - ❌ Assume syntax patterns without inspecting the AST first
Example - Inspecting AST:
rust
// In crates/biome_html_parser/tests/quick_test.rs
// Modify the quick_test function:
#[test]
pub fn quick_test() {
let code = r#"<button on:click={handleClick}>Click</button>"#;
let source_type = HtmlFileSource::svelte();
let options = HtmlParseOptions::from(&source_type);
let root = parse_html(code, options);
dbg!(&root.syntax()); // Shows full AST structure
}Run:
just qt biome_html_parser建议:
- ✅ 在实现前使用parser crate的检查AST结构
quick_test - ✅ 理解节点层级与父子关系
- ✅ 同时检查通用情况和特定类型(例如Vue同时有和
VueDirective)VueV*ShorthandDirective - ✅ 验证你的解决方案适用于所有相关变体类型,而非仅你找到的第一个类型
禁止:
- ❌ 仅为检查语法就构建完整的Biome二进制文件(成本高昂)——改用parser crate的
quick_test - ❌ 未先检查AST就假设语法模式
示例 - 检查AST:
rust
// In crates/biome_html_parser/tests/quick_test.rs
// Modify the quick_test function:
#[test]
pub fn quick_test() {
let code = r#"<button on:click={handleClick}>Click</button>"#;
let source_type = HtmlFileSource::svelte();
let options = HtmlParseOptions::from(&source_type);
let root = parse_html(code, options);
dbg!(&root.syntax()); // Shows full AST structure
}运行:
just qt biome_html_parserString Extraction and Text Handling
字符串提取与文本处理
DO:
- ✅ Use when extracting content from quoted strings (removes quotes)
inner_string_text() - ✅ Use when you need the full token text without leading/trailing whitespace
text_trimmed() - ✅ Use on nodes like
token_text_trimmed()to get the text contentHtmlAttributeName - ✅ Verify whether values use (quotes) or
HtmlString(curly braces)HtmlTextExpression
DON'T:
- ❌ Use when you need
text_trimmed()for extracting quoted string contentsinner_string_text()
Example - String Extraction:
rust
// WRONG: text_trimmed() includes quotes
let html_string = value.as_html_string()?;
let content = html_string.value_token()?.text_trimmed(); // Returns: "\"handler\""
// CORRECT: inner_string_text() removes quotes
let html_string = value.as_html_string()?;
let inner_text = html_string.inner_string_text().ok()?;
let content = inner_text.text(); // Returns: "handler"建议:
- ✅ 从带引号的字符串提取内容时使用(会移除引号)
inner_string_text() - ✅ 需要无首尾空白的完整令牌文本时使用
text_trimmed() - ✅ 从等节点获取文本内容时使用
HtmlAttributeNametoken_text_trimmed() - ✅ 验证值使用的是(带引号)还是
HtmlString(大括号)HtmlTextExpression
禁止:
- ❌ 提取带引号的字符串内容时使用(应使用
text_trimmed())inner_string_text()
示例 - 字符串提取:
rust
// WRONG: text_trimmed() includes quotes
let html_string = value.as_html_string()?;
let content = html_string.value_token()?.text_trimmed(); // Returns: "\"handler\""
// CORRECT: inner_string_text() removes quotes
let html_string = value.as_html_string()?;
let inner_text = html_string.inner_string_text().ok()?;
let content = inner_text.text(); // Returns: "handler"Working with Embedded Languages
处理嵌入式语言
DO:
- ✅ Verify changes work for different value formats (quoted strings vs text expressions) when handling multiple frameworks
- ✅ Use appropriate for context (Vue, Svelte, Astro, etc.)
EmbeddingKind - ✅ Check if embedded content needs (script tags) vs
is_source: true(template expressions)is_source: false - ✅ Calculate offsets correctly: token start + 1 for opening quote, or use for text expressions
text_range().start()
DON'T:
- ❌ Assume all frameworks use the same syntax (Vue uses quotes, Svelte uses curly braces)
- ❌ Implement features for "widely used" patterns without evidence - ask the user first
Example - Different Value Formats:
rust
// Vue directives use quoted strings: @click="handler"
let html_string = value.as_html_string()?;
let inner_text = html_string.inner_string_text().ok()?;
// Svelte directives use text expressions: on:click={handler}
let text_expression = value.as_html_attribute_single_text_expression()?;
let expression = text_expression.expression().ok()?;建议:
- ✅ 处理多框架时,验证更改适用于不同的值格式(带引号的字符串 vs 文本表达式)
- ✅ 根据上下文使用合适的(Vue、Svelte、Astro等)
EmbeddingKind - ✅ 检查嵌入式内容是否需要(脚本标签)或
is_source: true(模板表达式)is_source: false - ✅ 正确计算偏移量:令牌起始位置+1(针对开头引号),或对文本表达式使用
text_range().start()
禁止:
- ❌ 假设所有框架使用相同的语法(Vue使用引号,Svelte使用大括号)
- ❌ 无依据地为“广泛使用”的模式实现功能——先询问用户
示例 - 不同值格式:
rust
// Vue directives use quoted strings: @click="handler"
let html_string = value.as_html_string()?;
let inner_text = html_string.inner_string_text().ok()?;
// Svelte directives use text expressions: on:click={handler}
let text_expression = value.as_html_attribute_single_text_expression()?;
let expression = text_expression.expression().ok()?;Borrow Checker and Temporary Values
借用检查器与临时值
DO:
- ✅ Use intermediate bindings to avoid temporary value borrows that get dropped
let - ✅ Store method results that return owned values before calling methods on them
DON'T:
- ❌ Create temporary value borrows that get dropped before use
Example - Avoiding Borrow Issues:
rust
// WRONG: Temporary borrow gets dropped
let html_string = value.value().ok()?.as_html_string()?;
let token = html_string.value_token().ok()?; // ERROR: html_string dropped
// CORRECT: Store intermediate result
let value_node = value.value().ok()?;
let html_string = value_node.as_html_string()?;
let token = html_string.value_token().ok()?; // OK建议:
- ✅ 使用中间绑定避免临时值被提前释放导致的借用问题
let - ✅ 在调用方法前先存储返回自有值的方法结果
禁止:
- ❌ 创建会在使用前被释放的临时值借用
示例 - 避免借用问题:
rust
// WRONG: Temporary borrow gets dropped
let html_string = value.value().ok()?.as_html_string()?;
let token = html_string.value_token().ok()?; // ERROR: html_string dropped
// CORRECT: Store intermediate result
let value_node = value.value().ok()?;
let html_string = value_node.as_html_string()?;
let token = html_string.value_token().ok()?; // OKClippy and Code Style
Clippy与代码风格
DO:
- ✅ Use chains to collapse nested
letstatements (cleaner and follows Rust idioms)if let - ✅ Run before committing to catch clippy warnings
just l - ✅ Fix clippy suggestions unless there's a good reason not to
DON'T:
- ❌ Ignore clippy warnings - they often catch real issues or suggest better patterns
Example - Collapsible If:
rust
// WRONG: Nested if let (clippy::collapsible_if warning)
if let Some(directive) = VueDirective::cast_ref(&element) {
if let Some(initializer) = directive.initializer() {
// ... do something
}
}
// CORRECT: Use let chains
if let Some(directive) = VueDirective::cast_ref(&element)
&& let Some(initializer) = directive.initializer()
{
// ... do something
}建议:
- ✅ 使用链合并嵌套的
let语句(更简洁且符合Rust惯用写法)if let - ✅ 提交前运行捕获Clippy警告
just l - ✅ 除非有充分理由,否则修复Clippy建议的问题
禁止:
- ❌ 忽略Clippy警告——它们通常能发现实际问题或提供更优模式
示例 - 合并条件语句:
rust
// WRONG: Nested if let (clippy::collapsible_if warning)
if let Some(directive) = VueDirective::cast_ref(&element) {
if let Some(initializer) = directive.initializer() {
// ... do something
}
}
// CORRECT: Use let chains
if let Some(directive) = VueDirective::cast_ref(&element)
&& let Some(initializer) = directive.initializer()
{
// ... do something
}Legacy and Deprecated Syntax
遗留与已弃用语法
DO:
- ✅ Ask users before implementing deprecated/legacy syntax support
- ✅ Wait for user demand before spending time on legacy features
- ✅ Document when features are intentionally not supported due to being legacy
DON'T:
- ❌ Implement legacy/deprecated syntax without checking with the user first
- ❌ Claim patterns are "widely used" or "common" without evidence
Example:
Svelte's event handler syntax is legacy (Svelte 3/4). Modern Svelte 5 runes mode uses regular attributes. Unless users specifically request it, don't implement legacy syntax support.
on:click建议:
- ✅ 实现遗留/已弃用语法支持前先询问用户
- ✅ 有用户需求再投入时间开发遗留功能
- ✅ 记录因属于遗留特性而故意不支持的功能
禁止:
- ❌ 未先与用户确认就实现遗留/已弃用语法
- ❌ 无依据地宣称模式“广泛使用”或“常见”
示例:
Svelte的事件处理器语法属于遗留特性(Svelte 3/4)。现代Svelte 5的runes模式使用常规属性。除非用户明确要求,否则不要实现遗留语法支持。
on:clickTesting and Development
测试与开发
DO:
- ✅ Use to run quick tests (handles test execution automatically)
just qt <package> - ✅ Review snapshot changes carefully - don't blindly accept
- ✅ Test with multiple variants when working with enums (e.g., all types)
VueV*ShorthandDirective - ✅ Add tests for both valid and invalid cases
- ✅ Use CLI tests for testing embedded languages (Vue/Svelte directives, etc.)
DON'T:
- ❌ Blindly accept all snapshot changes
- ❌ Try to test embedded languages in analyzer packages (they don't have embedding capabilities)
建议:
- ✅ 使用运行快速测试(自动处理测试执行)
just qt <package> - ✅ 仔细审查快照变更——不要盲目接受
- ✅ 处理枚举时测试多个变体(例如所有类型)
VueV*ShorthandDirective - ✅ 为有效和无效案例都添加测试
- ✅ 使用CLI测试嵌入式语言(Vue/Svelte指令等)
禁止:
- ❌ 盲目接受所有快照变更
- ❌ 尝试在分析器包中测试嵌入式语言(它们不具备嵌入能力)
Pattern Matching Tips
模式匹配技巧
Working with Node Variants
处理节点变体
When working with enum variants (like ), check if there are also non-enum types that need handling:
AnySvelteDirectiverust
// Check AnySvelteDirective enum (bind:, class:, style:, etc.)
if let Some(directive) = AnySvelteDirective::cast_ref(&element) {
// Handle special Svelte directives
}
// But also check regular HTML attributes with specific prefixes
if let Some(attribute) = HtmlAttribute::cast_ref(&element) {
if let Ok(name) = attribute.name() {
// Some directives might be parsed as regular attributes
}
}处理枚举变体(如)时,检查是否还有非枚举类型需要处理:
AnySvelteDirectiverust
// Check AnySvelteDirective enum (bind:, class:, style:, etc.)
if let Some(directive) = AnySvelteDirective::cast_ref(&element) {
// Handle special Svelte directives
}
// But also check regular HTML attributes with specific prefixes
if let Some(attribute) = HtmlAttribute::cast_ref(&element) {
if let Ok(name) = attribute.name() {
// Some directives might be parsed as regular attributes
}
}Checking Multiple Variant Types
检查多种变体类型
For frameworks with multiple directive syntaxes, handle each type:
rust
// Vue has multiple shorthand types
if let Some(directive) = VueVOnShorthandDirective::cast_ref(&element) {
// Handle @click
}
if let Some(directive) = VueVBindShorthandDirective::cast_ref(&element) {
// Handle :prop
}
if let Some(directive) = VueVSlotShorthandDirective::cast_ref(&element) {
// Handle #slot
}
if let Some(directive) = VueDirective::cast_ref(&element) {
// Handle v-if, v-show, etc.
}针对有多种指令语法的框架,处理每种类型:
rust
// Vue has multiple shorthand types
if let Some(directive) = VueVOnShorthandDirective::cast_ref(&element) {
// Handle @click
}
if let Some(directive) = VueVBindShorthandDirective::cast_ref(&element) {
// Handle :prop
}
if let Some(directive) = VueVSlotShorthandDirective::cast_ref(&element) {
// Handle #slot
}
if let Some(directive) = VueDirective::cast_ref(&element) {
// Handle v-if, v-show, etc.
}Common API Confusion
常见API混淆点
String/Text Methods
字符串/文本方法
| Method | Use When | Returns |
|---|---|---|
| Extracting content from quoted strings | Content without quotes |
| Getting token text without whitespace | Full token text |
| Getting text from nodes like | Node text content |
| Getting raw text | Exact text as written |
| 方法 | 使用场景 | 返回值 |
|---|---|---|
| 从带引号的字符串提取内容 | 不带引号的内容 |
| 获取无空白的令牌文本 | 完整令牌文本 |
| 从 | 节点文本内容 |
| 获取原始文本 | 与书写完全一致的文本 |
Value Extraction Methods
值提取方法
| Type | Method | Framework |
|---|---|---|
| | Vue (quotes) |
| | Svelte (curly braces) |
| | Template expressions |
| 类型 | 方法 | 框架 |
|---|---|---|
| | Vue(带引号) |
| | Svelte(大括号) |
| | 模板表达式 |
References
参考资料
- Main contributing guide:
../../CONTRIBUTING.md - Testing workflows:
../testing-codegen/SKILL.md - Parser development:
../parser-development/SKILL.md - Biome internals docs: https://biomejs.dev/internals
- 主要贡献指南:
../../CONTRIBUTING.md - 测试工作流:
../testing-codegen/SKILL.md - 解析器开发:
../parser-development/SKILL.md - Biome内部文档:https://biomejs.dev/internals
Documentation and Markdown Formatting
文档与Markdown格式
DO:
- ✅ Use spaces around table separators: (not
| --- | --- | --- |)|---|---|---| - ✅ Ensure all Markdown tables follow "compact" style with proper spacing
- ✅ Test documentation changes with markdown linters before committing
DON'T:
- ❌ Use compact table separators without spaces (causes CI linting failures)
Example - Table Formatting:
markdown
<!-- WRONG: No spaces around separators -->
| Method | Use When | Returns |
|--------|----------|---------|
<!-- CORRECT: Spaces around separators -->
| Method | Use When | Returns |
| --- | --- | --- |The CI uses which enforces the "compact" style requiring spaces.
markdownlint-cli2建议:
- ✅ 表格分隔符前后使用空格:(而非
| --- | --- | --- |)|---|---|---| - ✅ 确保所有Markdown表格遵循“紧凑”风格并使用正确的空格
- ✅ 提交前使用markdown检查器测试文档变更
禁止:
- ❌ 使用无空格的紧凑表格分隔符(会导致CI检查失败)
示例 - 表格格式:
markdown
<!-- WRONG: No spaces around separators -->
| Method | Use When | Returns |
|--------|----------|---------|
<!-- CORRECT: Spaces around separators -->
| Method | Use When | Returns |
| --- | --- | --- |CI使用,它强制要求使用带空格的“紧凑”风格。
markdownlint-cli2When to Use This Skill
何时使用本技能
Load this skill when:
- Working with unfamiliar Biome APIs
- Getting borrow checker errors with temporary values
- Extracting strings or text from syntax nodes
- Implementing support for embedded languages (Vue, Svelte, etc.)
- Wondering why your AST inspection doesn't match expectations
- Making decisions about legacy/deprecated syntax support
- Writing or updating markdown documentation
在以下场景加载本技能:
- 处理不熟悉的Biome API
- 遇到临时值导致的借用检查器错误
- 从语法节点提取字符串或文本
- 实现嵌入式语言支持(Vue、Svelte等)
- 疑惑为何AST检查结果与预期不符
- 对遗留/已弃用语法支持做决策
- 编写或更新Markdown文档