Diagnostics & Error UI
Relevant source files
The following files were used as context for generating this wiki page:
The Diagnostics system in cheMD is a cross-cutting concern designed to provide real-time feedback to users during the document authoring process. It captures syntactic, semantic, and configuration-related issues across the compilation pipeline, from initial frontmatter parsing to final rendering. By attaching source-range information to these messages, the system enables the UI to highlight specific errors and warnings directly within the authoring environment.
The system ensures that errors remain local; a broken block or invalid render profile selection does not crash unrelated document sections. In the web interface, these diagnostics are surfaced through status indicators and dedicated panels, allowing for a tight feedback loop between the researcher and the structured data model.
Sources: chemd-v0.1-architecture.md:389-391, chemd-v0.1-architecture.md:405-407, apps/web/src/app/page.tsx:162-184
Diagnostic Data Model
The core of the system is the Diagnostic interface, which provides a standardized structure for reporting issues across different packages (parser, resolver, render-profile).
Structure and Severity
A diagnostic entry consists of a unique error code, a severity level, a human-readable message, and optional positioning metadata to link the error back to the source text.
| Field | Type | Description |
|---|---|---|
code | string | Unique identifier for the diagnostic type (e.g., E_DUPLICATE_ID). |
severity | "info" | "warning" | "error" | Impact level of the reported issue. |
message | string | Detailed explanation of the issue for the user. |
position | SourceRange | Optional start/end line and column numbers in the source file. |
nodeId | string | Optional reference to a specific AST node ID related to the issue. |
Sources: chemd-v0.1-architecture.md:393-401, chemd-v0.1-spec.md:586-591
Diagnostic Categories
The following diagram illustrates how diagnostics are categorized by their originating stage in the pipeline:
Pipeline Integration
Diagnostics are generated at every stage of the document processing pipeline. This allows the system to capture errors as early as possible while continuing to parse the remainder of the document.
Parser Stage
The parser identifies structural issues within the YAML frontmatter and the cheMD block syntax. It validates that required keys (id, title, date) are present and that dates follow the ISO YYYY-MM-DD format.
// Example of creating a frontmatter diagnostic
const createFrontmatterDiagnostic = (
code: string,
severity: Diagnostic["severity"],
message: string,
lineIndex: number,
lineText?: string,
token?: string
): Diagnostic => {
// ... logic to resolve line/column positions
return {
code,
severity,
message,
position: {
start: { line: lineIndex + 2, column: startColumn },
end: { line: lineIndex + 2, column: endColumn }
}
};
};
Sources: packages/parser/src/frontmatter/parse-frontmatter.ts:26-56, packages/parser/tests/parser.test.ts:404-415
Resolver Stage
The resolver builds an object index and validates relationships between components. It detects duplicate block IDs, unresolved @id.field references, and circular template expansions.
- E_DUPLICATE_ID: Triggered when two blocks share the same identifier.
- W_UNRESOLVED_REFERENCE: Triggered when a reference like
@res-main.yieldcannot be found in the index. - E_TEMPLATE_CYCLE: Detects recursive template calls that would cause infinite expansion.
Sources: packages/resolver/tests/resolver.test.ts:15-32, packages/resolver/tests/resolver.test.ts:246-265
User Interface & Presentation
In the apps/web playground, diagnostics are integrated into the real-time preview and editor feedback loop.
Compilation Status Indicator
The UI provides a summary "status pill" that reflects the current state of the document based on the diagnostic count and compilation freshness.
| State | Condition | UI Feedback |
|---|---|---|
pending | Source changed, compilation in progress | "Compiling..." |
success | 0 diagnostics found | "Preview synced" |
warning | Diagnostics > 0 | "X diagnostics" |
Sources: apps/web/src/app/page.tsx:94-100
HTML Rendering of Diagnostics
When rendering to HTML, diagnostics are appended as a list at the end of the document, allowing users to see issues in context with the rendered content.
export const renderHtml = (document: ChemdDocument, options: RenderOptions): string => {
// ... rendering logic
const diagnostics = document.diagnostics.length
? `<ul class="diagnostics">${document.diagnostics
.map(
(diagnostic) =>
`<li data-severity="${diagnostic.severity}">${escapeHtml(diagnostic.code)}: ${escapeHtml(diagnostic.message)}</li>`
)
.join("")}</ul>`
: "";
// ...
};
Sources: packages/renderer-html/src/index.ts:1088-1100
Real-time Feedback Loop
The editor uses a scheduler to perform background compilation, ensuring that diagnostic updates do not block user input.
Common Diagnostic Codes
| Code | Severity | Description |
|---|---|---|
E_MISSING_REQUIRED_FRONTMATTER_KEY | error | Required fields like id or title are missing in the header. |
W_NON_ISO_FRONTMATTER_DATE | warning | Date does not follow the YYYY-MM-DD format. |
E_DUPLICATE_ID | error | Multiple blocks found with the same ID. |
W_UNKNOWN_FIELD | warning | A field is provided in a block that is not recognized (e.g., bond_length in a molecule block). |
E_TEMPLATE_EXPANSION_LIMIT | error | Template expansion reached depth limit (preventing Denial of Service). |
Sources: chemd-v0.1-architecture.md:405-414, packages/parser/src/frontmatter/parse-frontmatter.ts:503-518, packages/resolver/tests/resolver.test.ts:318-348
The Diagnostics & Error UI system provides a robust framework for maintaining data integrity in cheMD documents. By separating semantic validation from rendering, it allows for clear, actionable feedback without interrupting the scientific documentation workflow.