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
43 lines
1.4 KiB
TypeScript
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, '');
|
|
}
|
|
}
|