Files
obsidian-mcp-server/src/utils/content-utils.ts
Bill f0808c0346 feat: add automatic word count and link validation to write operations
Add automatic word count and link validation to create_note, update_note,
and update_sections operations to provide immediate feedback on note content
quality and link integrity.

Features:
- Word counting excludes frontmatter and Obsidian comments, includes all
  other content (code blocks, inline code, headings, lists, etc.)
- Link validation checks wikilinks, heading links, and embeds
- Results categorized as: valid links, broken notes (note doesn't exist),
  and broken headings (note exists but heading missing)
- Detailed broken link info includes line number and context snippet
- Human-readable summary (e.g., "15 links: 12 valid, 2 broken notes, 1 broken heading")
- Opt-out capability via validateLinks parameter (default: true) for
  performance-critical operations

Implementation:
- New ContentUtils.countWords() for word counting logic
- Enhanced LinkUtils.validateLinks() for comprehensive link validation
- Updated create_note, update_note, update_sections to return wordCount
  and linkValidation fields
- Updated MCP tool descriptions to document new features and parameters
- update_note now returns structured JSON instead of simple success message

Response format changes:
- create_note: added wordCount and linkValidation fields
- update_note: changed to structured response with wordCount and linkValidation
- update_sections: added wordCount and linkValidation fields

Breaking changes:
- update_note response format changed from simple message to structured JSON
2025-10-30 11:14:45 -04:00

43 lines
1.4 KiB
TypeScript

import { FrontmatterUtils } from './frontmatter-utils';
/**
* Utility class for content analysis and manipulation
*/
export class ContentUtils {
/**
* Count words in content, excluding frontmatter and Obsidian comments
* Includes all other content: headings, paragraphs, lists, code blocks, inline code
*
* @param content The full markdown content to analyze
* @returns Word count (excludes frontmatter and Obsidian comments only)
*/
static countWords(content: string): number {
// Extract frontmatter to get content without it
const { contentWithoutFrontmatter } = FrontmatterUtils.extractFrontmatter(content);
// Remove Obsidian comments (%% ... %%)
// Handle both single-line and multi-line comments
const withoutComments = this.removeObsidianComments(contentWithoutFrontmatter);
// Split by whitespace and count non-empty tokens
const words = withoutComments
.split(/\s+/)
.filter(word => word.trim().length > 0);
return words.length;
}
/**
* Remove Obsidian comments from content
* Handles both %% single line %% and multi-line comments
*
* @param content Content to process
* @returns Content with Obsidian comments removed
*/
private static removeObsidianComments(content: string): string {
// Remove Obsidian comments: %% ... %%
// Use non-greedy match to handle multiple comments
return content.replace(/%%[\s\S]*?%%/g, '');
}
}