Files
md_reader/AGENTS.md
2026-03-18 20:12:14 +08:00

4.1 KiB

AGENTS.md - MD Reader

Markdown reader application.

Build & Run Commands

# Build project
cargo build
cargo build --release

# Run application
cargo run
cargo run -- --help

# Single binary output
cargo build --release
./target/release/md_reader

Node.js / Electron (Alternative)

# Install dependencies
npm install

# Development
npm run dev

# Production build
npm run build

# Run
npm start

Testing

Rust

# Run all tests
cargo test

# Run single test by name
cargo test test_name

# Run with output
cargo test -- --nocapture

# Doc tests
cargo test --doc

Node.js

# Run all tests
npm test

# Run single test file
npm test -- tests/single.test.ts

# Run tests in watch mode
npm run test:watch

# Coverage
npm run test:coverage

Linting & Formatting

Rust

# Format code (max_width=100, tab_spaces=4)
cargo fmt
cargo fmt -- --check

# Lint
cargo clippy
cargo clippy --all-features

# Check for errors
cargo check

Node.js

# Lint
npm run lint

# Format
npm run format

# Type check
npm run typecheck

Code Style

General

  • Keep lines under 100 characters
  • Use meaningful variable/function names
  • Document public APIs with doc comments

Rust Style

Imports (order: std → external → local)

use std::path::Path;
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};

use crate::core::parser::MarkdownParser;

Error Handling

  • Use anyhow::Result<T> for application code
  • Use thiserror for library code
  • Use .context() for error context
fn example() -> Result<SomeType> {
    let content = std::fs::read_to_string(path)
        .context("Failed to read markdown file")?;
    Ok(result)
}

Naming Conventions

  • Types/Enums: PascalCase (MarkdownDoc, NodeType)
  • Functions/Variables: snake_case (parse_markdown, render_html)
  • Files: snake_case (markdown_parser.rs)
  • Traits: PascalCase (Renderer, Parser)

Types

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MarkdownDoc {
    pub content: String,
    pub title: Option<String>,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum NodeType {
    Heading,
    Paragraph,
    CodeBlock,
}

Node.js Style

Imports

import { readFile } from 'fs/promises';
import { parse, Document } from 'markdown-it';
import type { Plugin } from './types';

Naming Conventions

  • Types/Interfaces: PascalCase (MarkdownDoc, RenderOptions)
  • Functions/Variables: camelCase (parseMarkdown, renderHtml)
  • Files: kebab-case (markdown-parser.ts, render-options.ts)

Error Handling

async function readMarkdown(path: string): Promise<string> {
  try {
    return await readFile(path, 'utf-8');
  } catch (error) {
    throw new Error(`Failed to read markdown: ${path}`, { cause: error });
  }
}

Project Structure

src/
├── main.rs              # Entry point (Rust)
├── lib.rs               # Library exports (Rust)
├── parser/              # Markdown parsing logic
├── renderer/            # Output rendering (HTML, PDF, etc.)
├── ui/                  # User interface components
└── utils/               # Utility functions

# Node.js alternative
src/
├── index.ts             # Entry point
├── parser/              # Markdown parsing
├── renderer/             # Rendering logic
├── ui/                  # UI components
└── utils/               # Utilities

Key Dependencies (Rust)

  • Error handling: anyhow, thiserror
  • Serialization: serde, serde_json
  • Markdown: pulldown-cmark or markdown
  • CLI: clap (derive)
  • Logging: tracing

Key Dependencies (Node.js)

  • Markdown parsing: markdown-it, marked, remark
  • UI: React or Vue
  • Build: vite, webpack
  • Testing: vitest, jest

Cursor Rules (from momentry_core)

  • No unit tests exist - add tests when implementing features
  • Focus on clean, maintainable code
  • Use appropriate abstractions
  • Keep modules focused and single-purpose