diagnostics-development

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Purpose

用途

Use this skill when creating diagnostics - the error messages, warnings, and hints shown to users. Covers the
Diagnostic
trait, advice types, and best practices for clear, actionable messages.
当你创建诊断信息(即展示给用户的错误消息、警告和提示)时,请使用本技能。内容涵盖
Diagnostic
trait、建议类型,以及编写清晰、可执行消息的最佳实践。

Prerequisites

前置条件

  1. Read
    crates/biome_diagnostics/CONTRIBUTING.md
    for concepts
  2. Understand Biome's Technical Principles
  3. Follow the "show don't tell" philosophy
  1. 阅读
    crates/biome_diagnostics/CONTRIBUTING.md
    了解相关概念
  2. 理解Biome的技术原则
  3. 遵循“展示而非告知”的理念

Diagnostic Principles

诊断信息原则

  1. Explain what - State what the error is (diagnostic message)
  2. Explain why - Explain why it's an error (advice notes)
  3. Tell how to fix - Provide actionable fixes (code actions, diff advice, command advice)
Follow Technical Principles:
  • Informative: Explain, don't just state
  • Concise: Short messages, rich context via advices
  • Actionable: Always suggest how to fix
  • Show don't tell: Prefer code frames over textual explanations
  1. 说明问题是什么 - 明确指出错误内容(诊断消息)
  2. 说明问题原因 - 解释为什么这是一个错误(建议说明)
  3. 说明修复方法 - 提供可执行的修复方案(代码操作、差异建议、命令建议)
遵循技术原则:
  • 信息丰富:解释原因,而非仅陈述事实
  • 简洁明了:消息简短,通过建议提供丰富上下文
  • 可执行:始终给出修复建议
  • 展示而非告知:优先使用代码框而非文字解释

Common Workflows

常见工作流程

Create a Diagnostic Type

创建诊断类型

Use the
#[derive(Diagnostic)]
macro:
rust
use biome_diagnostics::{Diagnostic, category};

#[derive(Debug, Diagnostic)]
#[diagnostic(
    severity = Error,
    category = "lint/correctness/noVar"
)]
struct NoVarDiagnostic {
    #[location(span)]
    span: TextRange,
    
    #[message]
    #[description]
    message: MessageAndDescription,
    
    #[advice]
    advice: NoVarAdvice,
}

#[derive(Debug)]
struct MessageAndDescription;

impl fmt::Display for MessageAndDescription {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Use 'let' or 'const' instead of 'var'")
    }
}
使用
#[derive(Diagnostic)]
宏:
rust
use biome_diagnostics::{Diagnostic, category};

#[derive(Debug, Diagnostic)]
#[diagnostic(
    severity = Error,
    category = "lint/correctness/noVar"
)]
struct NoVarDiagnostic {
    #[location(span)]
    span: TextRange,
    
    #[message]
    #[description]
    message: MessageAndDescription,
    
    #[advice]
    advice: NoVarAdvice,
}

#[derive(Debug)]
struct MessageAndDescription;

impl fmt::Display for MessageAndDescription {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Use 'let' or 'const' instead of 'var'")
    }
}

Implement Advices

实现建议类型

Create advice types that implement
Advices
trait:
rust
use biome_diagnostics::{Advices, Visit};
use biome_console::markup;

struct NoVarAdvice {
    is_const_candidate: bool,
}

impl Advices for NoVarAdvice {
    fn record(&self, visitor: &mut dyn Visit) -> std::io::Result<()> {
        if self.is_const_candidate {
            visitor.record_log(
                LogCategory::Info,
                &markup! {
                    "This variable is never reassigned, use 'const' instead."
                }
            )?;
        } else {
            visitor.record_log(
                LogCategory::Info,
                &markup! {
                    "Variables declared with 'var' are function-scoped, use 'let' for block-scoping."
                }
            )?;
        }
        Ok(())
    }
}
创建实现
Advices
trait的建议类型:
rust
use biome_diagnostics::{Advices, Visit};
use biome_console::markup;

struct NoVarAdvice {
    is_const_candidate: bool,
}

impl Advices for NoVarAdvice {
    fn record(&self, visitor: &mut dyn Visit) -> std::io::Result<()> {
        if self.is_const_candidate {
            visitor.record_log(
                LogCategory::Info,
                &markup! {
                    "This variable is never reassigned, use 'const' instead."
                }
            )?;
        } else {
            visitor.record_log(
                LogCategory::Info,
                &markup! {
                    "Variables declared with 'var' are function-scoped, use 'let' for block-scoping."
                }
            )?;
        }
        Ok(())
    }
}

Use Built-in Advice Types

使用内置建议类型

rust
use biome_diagnostics::v2::{
    LogAdvice, CodeFrameAdvice, DiffAdvice, CommandAdvice
};

// Log advice - simple text
LogAdvice {
    category: LogCategory::Info,
    message: markup! { "Consider using arrow functions." }
}

// Code frame advice - highlight code location
CodeFrameAdvice {
    location: node.text_range(),
    source_code: ctx.source_code(),
    annotation: markup! { "This code is problematic" },
}

// Diff advice - show before/after
DiffAdvice {
    old: "var x = 1;",
    new: "const x = 1;",
}

// Command advice - suggest CLI command
CommandAdvice {
    command: "biome check --apply",
    message: markup! { "Run this command to fix automatically" },
}
rust
use biome_diagnostics::v2::{
    LogAdvice, CodeFrameAdvice, DiffAdvice, CommandAdvice
};

// Log advice - simple text
LogAdvice {
    category: LogCategory::Info,
    message: markup! { "Consider using arrow functions." }
}

// Code frame advice - highlight code location
CodeFrameAdvice {
    location: node.text_range(),
    source_code: ctx.source_code(),
    annotation: markup! { "This code is problematic" },
}

// Diff advice - show before/after
DiffAdvice {
    old: "var x = 1;",
    new: "const x = 1;",
}

// Command advice - suggest CLI command
CommandAdvice {
    command: "biome check --apply",
    message: markup! { "Run this command to fix automatically" },
}

Add Diagnostic to Rule

为规则添加诊断信息

rust
use biome_analyze::{Rule, RuleDiagnostic};

impl Rule for NoVar {
    fn diagnostic(ctx: &RuleContext<Self>, state: &Self::State) -> Option<RuleDiagnostic> {
        let node = ctx.query();
        
        Some(
            RuleDiagnostic::new(
                rule_category!(),
                node.range(),
                markup! {
                    "Use "<Emphasis>"let"</Emphasis>" or "<Emphasis>"const"</Emphasis>" instead of "<Emphasis>"var"</Emphasis>"."
                },
            )
            .note(markup! {
                "Variables declared with "<Emphasis>"var"</Emphasis>" are function-scoped, not block-scoped."
            })
            .note(markup! {
                "See the "<Hyperlink href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/var">"MDN documentation"</Hyperlink>" for more details."
            })
        )
    }
}
rust
use biome_analyze::{Rule, RuleDiagnostic};

impl Rule for NoVar {
    fn diagnostic(ctx: &RuleContext<Self>, state: &Self::State) -> Option<RuleDiagnostic> {
        let node = ctx.query();
        
        Some(
            RuleDiagnostic::new(
                rule_category!(),
                node.range(),
                markup! {
                    "Use "<Emphasis>"let"</Emphasis>" or "<Emphasis>"const"</Emphasis>" instead of "<Emphasis>"var"</Emphasis>"."
                },
            )
            .note(markup! {
                "Variables declared with "<Emphasis>"var"</Emphasis>" are function-scoped, not block-scoped."
            })
            .note(markup! {
                "See the "<Hyperlink href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/var">"MDN documentation"</Hyperlink>" for more details."
            })
        )
    }
}

Use Markup for Rich Text

使用标记语法实现富文本

Biome supports rich markup in diagnostic messages:
rust
use biome_console::markup;

markup! {
    // Emphasis (bold/colored)
    "Use "<Emphasis>"const"</Emphasis>" instead."
    
    // Code/identifiers
    "The variable "<Emphasis>{variable_name}</Emphasis>" is never used."
    
    // Hyperlinks
    "See the "<Hyperlink href="https://example.com">"documentation"</Hyperlink>"."
    
    // Interpolation
    "Found "{count}" issues."
}
Biome支持在诊断消息中使用富文本标记:
rust
use biome_console::markup;

markup! {
    // Emphasis (bold/colored)
    "Use "<Emphasis>"const"</Emphasis>" instead."
    
    // Code/identifiers
    "The variable "<Emphasis>{variable_name}</Emphasis>" is never used."
    
    // Hyperlinks
    "See the "<Hyperlink href="https://example.com">"documentation"</Hyperlink>"."
    
    // Interpolation
    "Found "{count}" issues."
}

Register Diagnostic Category

注册诊断信息分类

Add new categories to
crates/biome_diagnostics_categories/src/categories.rs
:
rust
define_categories! {
    // Existing categories...
    
    "lint/correctness/noVar": "https://biomejs.dev/linter/rules/no-var",
    "lint/style/useConst": "https://biomejs.dev/linter/rules/use-const",
}
将新分类添加到
crates/biome_diagnostics_categories/src/categories.rs
rust
define_categories! {
    // Existing categories...
    
    "lint/correctness/noVar": "https://biomejs.dev/linter/rules/no-var",
    "lint/style/useConst": "https://biomejs.dev/linter/rules/use-const",
}

Create Multi-Advice Diagnostics

创建多建议诊断信息

rust
#[derive(Debug, Diagnostic)]
#[diagnostic(severity = Warning)]
struct ComplexDiagnostic {
    #[location(span)]
    span: TextRange,
    
    #[message]
    message: &'static str,
    
    // Multiple advices
    #[advice]
    first_advice: LogAdvice,
    
    #[advice]
    code_frame: CodeFrameAdvice,
    
    #[verbose_advice]
    verbose_help: LogAdvice,
}
rust
#[derive(Debug, Diagnostic)]
#[diagnostic(severity = Warning)]
struct ComplexDiagnostic {
    #[location(span)]
    span: TextRange,
    
    #[message]
    message: &'static str,
    
    // Multiple advices
    #[advice]
    first_advice: LogAdvice,
    
    #[advice]
    code_frame: CodeFrameAdvice,
    
    #[verbose_advice]
    verbose_help: LogAdvice,
}

Add Tags to Diagnostics

为诊断信息添加标签

rust
#[derive(Debug, Diagnostic)]
#[diagnostic(
    severity = Warning,
    tags(FIXABLE, DEPRECATED_CODE)  // Add diagnostic tags
)]
struct MyDiagnostic {
    // ...
}
Available tags:
  • FIXABLE
    - Diagnostic has fix information
  • INTERNAL
    - Internal error in Biome
  • UNNECESSARY_CODE
    - Code is unused
  • DEPRECATED_CODE
    - Code uses deprecated features
rust
#[derive(Debug, Diagnostic)]
#[diagnostic(
    severity = Warning,
    tags(FIXABLE, DEPRECATED_CODE)  // Add diagnostic tags
)]
struct MyDiagnostic {
    // ...
}
可用标签:
  • FIXABLE
    - 诊断信息包含修复方案
  • INTERNAL
    - Biome内部错误
  • UNNECESSARY_CODE
    - 代码未被使用
  • DEPRECATED_CODE
    - 代码使用了已废弃的特性

Best Practices

最佳实践

Message Guidelines

消息指南

Good messages:
rust
// ✅ Specific and actionable
"Use 'let' or 'const' instead of 'var'"

// ✅ Explains why
"This variable is never reassigned, consider using 'const'"

// ✅ Shows what to do
"Remove the unused import statement"
Bad messages:
rust
// ❌ Too vague
"Invalid syntax"

// ❌ Just states the obvious
"Variable declared with 'var'"

// ❌ No guidance
"This code has a problem"
优秀的消息示例:
rust
// ✅ Specific and actionable
"Use 'let' or 'const' instead of 'var'"

// ✅ Explains why
"This variable is never reassigned, consider using 'const'"

// ✅ Shows what to do
"Remove the unused import statement"
不佳的消息示例:
rust
// ❌ Too vague
"Invalid syntax"

// ❌ Just states the obvious
"Variable declared with 'var'"

// ❌ No guidance
"This code has a problem"

Advice Guidelines

建议指南

Show, don't tell:
rust
// ✅ Good - shows code frame
CodeFrameAdvice {
    location: node.range(),
    source_code: source,
    annotation: markup! { "This expression is always truthy" }
}

// ❌ Less helpful - just text
LogAdvice {
    message: markup! { "The expression at line 5 is always truthy" }
}
Provide actionable fixes:
rust
// ✅ Good - shows exact change
DiffAdvice {
    old: "var x = 1;",
    new: "const x = 1;",
}

// ❌ Less helpful - describes change
LogAdvice {
    message: markup! { "Change 'var' to 'const'" }
}
展示而非告知:
rust
// ✅ Good - shows code frame
CodeFrameAdvice {
    location: node.range(),
    source_code: source,
    annotation: markup! { "This expression is always truthy" }
}

// ❌ Less helpful - just text
LogAdvice {
    message: markup! { "The expression at line 5 is always truthy" }
}
提供可执行的修复方案:
rust
// ✅ Good - shows exact change
DiffAdvice {
    old: "var x = 1;",
    new: "const x = 1;",
}

// ❌ Less helpful - describes change
LogAdvice {
    message: markup! { "Change 'var' to 'const'" }
}

Severity Levels

严重级别

Choose appropriate severity:
rust
// Fatal - Biome can't continue
severity = Fatal

// Error - Must be fixed (correctness, security, a11y)
severity = Error

// Warning - Should be fixed (suspicious code)
severity = Warning

// Information - Style suggestions
severity = Information

// Hint - Minor improvements
severity = Hint
选择合适的严重级别:
rust
// Fatal - Biome can't continue
severity = Fatal

// Error - Must be fixed (correctness, security, a11y)
severity = Error

// Warning - Should be fixed (suspicious code)
severity = Warning

// Information - Style suggestions
severity = Information

// Hint - Minor improvements
severity = Hint

Common Patterns

常见模式

rust
// Pattern 1: Simple diagnostic with note
RuleDiagnostic::new(
    rule_category!(),
    node.range(),
    markup! { "Main message" },
)
.note(markup! { "Additional context" })

// Pattern 2: Diagnostic with code frame
RuleDiagnostic::new(
    rule_category!(),
    node.range(),
    markup! { "Main message" },
)
.detail(
    node.syntax().text_range(),
    markup! { "This part is problematic" }
)

// Pattern 3: Diagnostic with link
RuleDiagnostic::new(
    rule_category!(),
    node.range(),
    markup! { "Main message" },
)
.note(markup! {
    "See "<Hyperlink href="https://biomejs.dev/linter">"documentation"</Hyperlink>"."
})

// Pattern 4: Conditional advice
impl Advices for MyAdvice {
    fn record(&self, visitor: &mut dyn Visit) -> std::io::Result<()> {
        if self.show_hint {
            visitor.record_log(
                LogCategory::Info,
                &markup! { "Hint: ..." }
            )?;
        }
        Ok(())
    }
}
rust
// Pattern 1: Simple diagnostic with note
RuleDiagnostic::new(
    rule_category!(),
    node.range(),
    markup! { "Main message" },
)
.note(markup! { "Additional context" })

// Pattern 2: Diagnostic with code frame
RuleDiagnostic::new(
    rule_category!(),
    node.range(),
    markup! { "Main message" },
)
.detail(
    node.syntax().text_range(),
    markup! { "This part is problematic" }
)

// Pattern 3: Diagnostic with link
RuleDiagnostic::new(
    rule_category!(),
    node.range(),
    markup! { "Main message" },
)
.note(markup! {
    "See "<Hyperlink href="https://biomejs.dev/linter">"documentation"</Hyperlink>"."
})

// Pattern 4: Conditional advice
impl Advices for MyAdvice {
    fn record(&self, visitor: &mut dyn Visit) -> std::io::Result<()> {
        if self.show_hint {
            visitor.record_log(
                LogCategory::Info,
                &markup! { "Hint: ..." }
            )?;
        }
        Ok(())
    }
}

Tips

提示

  • Category format: Use
    area/group/ruleName
    format (e.g.,
    lint/correctness/noVar
    )
  • Markup formatting: Use
    markup!
    macro for all user-facing text
  • Hyperlinks: Always link to documentation for more details
  • Code frames: Include for spatial context when helpful
  • Multiple advices: Chain multiple pieces of information
  • Verbose advices: Use for extra details users can opt into
  • Description vs Message: Description for plain text contexts (IDE popover), message for rich display
  • Register categories: Don't forget to add to
    categories.rs
  • 分类格式:使用
    area/group/ruleName
    格式(例如
    lint/correctness/noVar
  • 标记语法:所有面向用户的文本都使用
    markup!
  • 超链接:始终链接到相关文档以提供更多细节
  • 代码框:在需要空间上下文时添加代码框
  • 多建议:串联多条信息
  • 详细建议:用于用户可选择查看的额外细节
  • 描述与消息的区别:描述用于纯文本场景(如IDE弹出框),消息用于富文本展示
  • 注册分类:不要忘记添加到
    categories.rs

References

参考资料

  • Full guide:
    crates/biome_diagnostics/CONTRIBUTING.md
  • Technical principles: https://biomejs.dev/internals/philosophy/#technical
  • Diagnostic trait:
    crates/biome_diagnostics/src/diagnostic.rs
  • Advice types:
    crates/biome_diagnostics/src/v2/
  • Examples: Search for
    #[derive(Diagnostic)]
    in codebase
  • 完整指南:
    crates/biome_diagnostics/CONTRIBUTING.md
  • 技术原则:https://biomejs.dev/internals/philosophy/#technical
  • Diagnostic trait:
    crates/biome_diagnostics/src/diagnostic.rs
  • 建议类型:
    crates/biome_diagnostics/src/v2/
  • 示例:在代码库中搜索
    #[derive(Diagnostic)]