Markdown Anchor Links and Fragment Identifiers: Complete Guide to Document Navigation and Cross-Referencing
Markdown anchor links and fragment identifiers enable sophisticated document navigation through internal linking systems, cross-referencing capabilities, and dynamic content organization. By implementing proper anchor link structures, automatic heading ID generation, and accessible navigation patterns, technical writers and developers can create comprehensive documentation that allows users to navigate complex content efficiently while maintaining proper linking integrity and search engine optimization.
Why Master Anchor Links and Fragment Identifiers?
Advanced document navigation provides essential benefits for content organization and user experience:
- Enhanced Navigation: Create seamless internal linking systems for quick content access
- Improved User Experience: Enable direct linking to specific document sections and content
- SEO Optimization: Implement proper fragment identifiers for search engine discoverability
- Accessibility Enhancement: Provide clear navigation paths for screen readers and assistive technologies
- Content Organization: Structure documents with logical navigation hierarchies and cross-references
Foundation Anchor Link Principles
Basic Anchor Link Syntax
Understanding the fundamental structure of Markdown anchor links and fragment identifiers:
# Basic Anchor Link Patterns
## Heading-Based Anchors
### Automatic Heading Anchors
When you create headings in Markdown, most processors automatically generate anchor IDs:
# Main Title
## Section Overview
### Detailed Information
These automatically become linkable as:
- `#main-title`
- `#section-overview`
- `#detailed-information`
### Manual Anchor Links
Link directly to sections using fragment identifiers:
[Jump to Section Overview](#section-overview)
[Go to Detailed Information](#detailed-information)
## Custom Anchor Points
### HTML Anchor Elements
Create custom anchor points anywhere in your document:
<a id="custom-anchor"></a>
This paragraph can be linked to directly.
[Link to custom anchor](#custom-anchor)
### Heading ID Override
Explicitly set heading IDs for better control:
## Section Title {#custom-id}
[Link to custom section](#custom-id)
## Table of Contents Example
### Document Structure
1. [Introduction](#introduction)
2. [Getting Started](#getting-started)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
3. [Usage Examples](#usage-examples)
- [Basic Usage](#basic-usage)
- [Advanced Features](#advanced-features)
4. [Troubleshooting](#troubleshooting)
5. [Conclusion](#conclusion)
## Cross-Document References
### Linking to External Documents
Reference sections in other Markdown files:
[See API Documentation](api-reference.md#authentication)
[View Installation Guide](setup.md#requirements)
### Relative Path Navigation
Navigate between related documentation:
[Previous: Setup](../setup/installation.md)
[Next: Configuration](./configuration.md#basic-config)
Automatic ID Generation Patterns
Understanding how different Markdown processors handle automatic anchor ID generation:
# Automatic ID Generation Rules
## Standard ID Conversion Patterns
### Text Transformation Rules
Heading text undergoes specific transformations to create valid IDs:
#### Original Headings → Generated IDs
- "Getting Started" → `getting-started`
- "API Reference Guide" → `api-reference-guide`
- "User Authentication & Security" → `user-authentication--security`
- "FAQ: Common Questions" → `faq-common-questions`
- "Version 2.0 Release Notes" → `version-20-release-notes`
### Special Character Handling
Different processors handle special characters differently:
#### GitHub Flavored Markdown (GFM)
- Converts to lowercase
- Replaces spaces with hyphens
- Removes most special characters
- Preserves numbers and letters
#### GitLab Markdown
- Similar to GFM but with slight variations
- Better Unicode support
- Different handling of consecutive spaces
#### Hugo Markdown
- More aggressive special character removal
- Optional custom ID generation functions
- Configurable transformation rules
### Duplicate Heading Handling
When multiple headings have the same text:
## Overview
Content for first overview section.
## Overview {#overview-2}
Content for second overview section.
## Overview {#detailed-overview}
Content for third overview section with custom ID.
### Non-ASCII Character Support
International characters and Unicode handling:
## Configuración Inicial → `configuración-inicial`
## データベース設定 → `データベース設定` (if Unicode supported)
## Εισαγωγή → `εισαγωγή` (Greek example)
### Best Practices for Predictable IDs
1. Use descriptive, unique heading text
2. Avoid special characters when possible
3. Test ID generation across target platforms
4. Provide explicit IDs for critical sections
5. Document ID naming conventions for teams
Advanced Navigation Implementation
JavaScript-Enhanced Navigation
Creating dynamic table of contents and smooth scrolling functionality:
// markdown-navigation-enhancer.js - Advanced anchor link functionality
class MarkdownNavigationEnhancer {
constructor(options = {}) {
this.options = {
smoothScrolling: true,
generateTOC: true,
highlightActive: true,
updateURL: true,
scrollOffset: 80,
animationDuration: 800,
activeClass: 'active',
tocSelector: '.table-of-contents',
headingSelector: 'h1, h2, h3, h4, h5, h6',
...options
};
this.headings = [];
this.tocContainer = null;
this.activeSection = null;
this.scrollTimeout = null;
this.initialize();
}
initialize() {
this.collectHeadings();
this.ensureHeadingIDs();
if (this.options.generateTOC) {
this.generateTableOfContents();
}
if (this.options.smoothScrolling) {
this.setupSmoothScrolling();
}
if (this.options.highlightActive) {
this.setupActiveHighlighting();
}
this.handleInitialHash();
this.setupEventListeners();
}
collectHeadings() {
const headingElements = document.querySelectorAll(this.options.headingSelector);
this.headings = Array.from(headingElements).map((heading, index) => {
const level = parseInt(heading.tagName.charAt(1));
const text = heading.textContent.trim();
const id = heading.id || this.generateHeadingID(text, index);
// Ensure heading has an ID
if (!heading.id) {
heading.id = id;
}
return {
element: heading,
id: id,
text: text,
level: level,
offsetTop: heading.getBoundingClientRect().top + window.pageYOffset
};
});
}
generateHeadingID(text, fallbackIndex) {
// Convert heading text to valid anchor ID
let id = text
.toLowerCase()
.trim()
.replace(/[^\w\s-]/g, '') // Remove special characters except hyphens
.replace(/\s+/g, '-') // Replace spaces with hyphens
.replace(/-+/g, '-') // Replace multiple hyphens with single
.replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
// Handle empty results
if (!id) {
id = `heading-${fallbackIndex}`;
}
// Handle duplicates
let finalId = id;
let counter = 1;
while (document.getElementById(finalId)) {
finalId = `${id}-${counter}`;
counter++;
}
return finalId;
}
ensureHeadingIDs() {
this.headings.forEach(heading => {
if (!heading.element.id) {
heading.element.id = heading.id;
}
});
}
generateTableOfContents() {
const tocContainer = document.querySelector(this.options.tocSelector);
if (!tocContainer) {
return this.createTOCContainer();
}
this.tocContainer = tocContainer;
this.renderTOC();
}
createTOCContainer() {
// Create TOC container if it doesn't exist
const tocContainer = document.createElement('div');
tocContainer.className = 'table-of-contents';
tocContainer.innerHTML = `
<h3>Table of Contents</h3>
<nav class="toc-nav" role="navigation" aria-label="Table of Contents">
<ul class="toc-list"></ul>
</nav>
`;
// Insert after first heading or at beginning of main content
const firstHeading = document.querySelector(this.options.headingSelector);
if (firstHeading) {
firstHeading.parentNode.insertBefore(tocContainer, firstHeading);
} else {
const main = document.querySelector('main, article, .content');
if (main) {
main.insertBefore(tocContainer, main.firstChild);
}
}
this.tocContainer = tocContainer;
this.renderTOC();
}
renderTOC() {
if (!this.tocContainer) return;
const tocList = this.tocContainer.querySelector('.toc-list') ||
this.tocContainer.querySelector('ul');
if (!tocList) return;
// Build nested TOC structure
const tocHTML = this.buildTOCHTML(this.headings);
tocList.innerHTML = tocHTML;
// Add click handlers for TOC links
const tocLinks = tocList.querySelectorAll('a[href^="#"]');
tocLinks.forEach(link => {
link.addEventListener('click', (e) => {
this.handleAnchorClick(e);
});
});
}
buildTOCHTML(headings) {
if (headings.length === 0) return '';
let html = '';
let currentLevel = 0;
let stack = [];
headings.forEach((heading, index) => {
const { level, id, text } = heading;
if (level > currentLevel) {
// Open new nested levels
for (let i = currentLevel; i < level - 1; i++) {
html += '<li><ul>';
stack.push('</ul></li>');
}
if (currentLevel > 0) {
html += '<li><ul>';
stack.push('</ul></li>');
}
} else if (level < currentLevel) {
// Close nested levels
const levelsToClose = currentLevel - level;
for (let i = 0; i < levelsToClose; i++) {
html += stack.pop() || '';
}
html += '</li>';
} else if (currentLevel > 0) {
html += '</li>';
}
// Add the current heading
html += `<li><a href="#${id}" class="toc-link toc-level-${level}">${this.escapeHTML(text)}</a>`;
currentLevel = level;
});
// Close remaining open tags
html += '</li>';
while (stack.length > 0) {
html += stack.pop();
}
return html;
}
setupSmoothScrolling() {
// Handle all anchor links on the page
const anchorLinks = document.querySelectorAll('a[href^="#"]');
anchorLinks.forEach(link => {
link.addEventListener('click', (e) => {
this.handleAnchorClick(e);
});
});
}
handleAnchorClick(event) {
event.preventDefault();
const targetId = event.target.getAttribute('href').substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
this.scrollToElement(targetElement);
if (this.options.updateURL) {
history.pushState(null, '', `#${targetId}`);
}
}
}
scrollToElement(element) {
const offsetTop = element.getBoundingClientRect().top + window.pageYOffset;
const targetPosition = offsetTop - this.options.scrollOffset;
if (this.options.smoothScrolling) {
this.smoothScrollTo(targetPosition);
} else {
window.scrollTo(0, targetPosition);
}
// Focus the element for accessibility
this.focusElement(element);
}
smoothScrollTo(targetPosition) {
const startPosition = window.pageYOffset;
const distance = targetPosition - startPosition;
const duration = this.options.animationDuration;
let start = null;
const animation = (currentTime) => {
if (start === null) start = currentTime;
const timeElapsed = currentTime - start;
const run = this.easeInOutCubic(timeElapsed, startPosition, distance, duration);
window.scrollTo(0, run);
if (timeElapsed < duration) {
requestAnimationFrame(animation);
}
};
requestAnimationFrame(animation);
}
easeInOutCubic(t, b, c, d) {
t /= d / 2;
if (t < 1) return c / 2 * t * t * t + b;
t -= 2;
return c / 2 * (t * t * t + 2) + b;
}
focusElement(element) {
// Set focus for accessibility, with fallback for non-focusable elements
if (!element.getAttribute('tabindex')) {
element.setAttribute('tabindex', '-1');
}
element.focus({ preventScroll: true });
// Remove tabindex after focus to maintain natural tab order
setTimeout(() => {
if (element.getAttribute('tabindex') === '-1') {
element.removeAttribute('tabindex');
}
}, 100);
}
setupActiveHighlighting() {
// Create intersection observer for active section highlighting
this.intersectionObserver = new IntersectionObserver(
(entries) => {
this.handleIntersection(entries);
},
{
threshold: [0, 0.25, 0.5, 0.75, 1.0],
rootMargin: `-${this.options.scrollOffset}px 0px -75% 0px`
}
);
// Observe all headings
this.headings.forEach(heading => {
this.intersectionObserver.observe(heading.element);
});
// Fallback scroll-based highlighting
window.addEventListener('scroll', this.throttle(() => {
this.updateActiveSection();
}, 100), { passive: true });
}
handleIntersection(entries) {
entries.forEach(entry => {
const heading = this.headings.find(h => h.element === entry.target);
if (heading && entry.isIntersecting && entry.intersectionRatio > 0.5) {
this.setActiveSection(heading.id);
}
});
}
updateActiveSection() {
const scrollPosition = window.pageYOffset + this.options.scrollOffset;
// Find the current section based on scroll position
let activeHeading = null;
for (let i = this.headings.length - 1; i >= 0; i--) {
const heading = this.headings[i];
const offsetTop = heading.element.getBoundingClientRect().top + window.pageYOffset;
if (scrollPosition >= offsetTop - 10) {
activeHeading = heading;
break;
}
}
if (activeHeading) {
this.setActiveSection(activeHeading.id);
}
}
setActiveSection(sectionId) {
if (this.activeSection === sectionId) return;
this.activeSection = sectionId;
// Update TOC highlighting
if (this.tocContainer) {
const tocLinks = this.tocContainer.querySelectorAll('.toc-link');
tocLinks.forEach(link => {
link.classList.remove(this.options.activeClass);
});
const activeLink = this.tocContainer.querySelector(`a[href="#${sectionId}"]`);
if (activeLink) {
activeLink.classList.add(this.options.activeClass);
}
}
// Update section highlighting
this.headings.forEach(heading => {
heading.element.classList.remove(this.options.activeClass);
});
const activeHeading = document.getElementById(sectionId);
if (activeHeading) {
activeHeading.classList.add(this.options.activeClass);
}
}
handleInitialHash() {
// Handle page load with hash fragment
if (window.location.hash) {
const targetId = window.location.hash.substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
// Delay scroll to ensure page is fully loaded
setTimeout(() => {
this.scrollToElement(targetElement);
}, 100);
}
}
}
setupEventListeners() {
// Handle browser back/forward navigation
window.addEventListener('popstate', () => {
this.handleInitialHash();
});
// Handle dynamic content changes
const observer = new MutationObserver(() => {
this.refresh();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
// Handle window resize
window.addEventListener('resize', this.throttle(() => {
this.updateHeadingPositions();
}, 250));
}
updateHeadingPositions() {
this.headings.forEach(heading => {
heading.offsetTop = heading.element.getBoundingClientRect().top + window.pageYOffset;
});
}
refresh() {
// Re-collect headings and regenerate TOC
this.headings = [];
this.collectHeadings();
this.ensureHeadingIDs();
if (this.options.generateTOC && this.tocContainer) {
this.renderTOC();
}
if (this.intersectionObserver) {
this.intersectionObserver.disconnect();
this.setupActiveHighlighting();
}
}
throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
escapeHTML(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Public API methods
scrollToSection(sectionId) {
const element = document.getElementById(sectionId);
if (element) {
this.scrollToElement(element);
}
}
getActiveSection() {
return this.activeSection;
}
getTOC() {
return this.headings.map(heading => ({
id: heading.id,
text: heading.text,
level: heading.level
}));
}
destroy() {
if (this.intersectionObserver) {
this.intersectionObserver.disconnect();
}
// Remove event listeners and clean up
const anchorLinks = document.querySelectorAll('a[href^="#"]');
anchorLinks.forEach(link => {
link.removeEventListener('click', this.handleAnchorClick);
});
}
}
// Auto-initialize navigation enhancement
document.addEventListener('DOMContentLoaded', function() {
// Check if page has headings before initializing
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
if (headings.length > 2) {
window.markdownNav = new MarkdownNavigationEnhancer({
smoothScrolling: true,
generateTOC: !document.querySelector('.table-of-contents'),
highlightActive: true,
scrollOffset: 80
});
}
});
CSS Styling for Enhanced Navigation
Comprehensive styling for anchor links and navigation elements:
/* markdown-navigation.css - Advanced anchor link and TOC styling */
/* Table of Contents Styling */
.table-of-contents {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 1.5rem;
margin: 2rem 0;
position: relative;
}
.table-of-contents h3 {
margin: 0 0 1rem 0;
color: #495057;
font-size: 1.1rem;
font-weight: 600;
border-bottom: 2px solid #dee2e6;
padding-bottom: 0.5rem;
}
.toc-nav {
font-size: 0.9rem;
}
.toc-list {
list-style: none;
margin: 0;
padding: 0;
line-height: 1.6;
}
.toc-list li {
margin: 0;
padding: 0;
}
.toc-list ul {
list-style: none;
margin: 0.5rem 0 0.5rem 1.2rem;
padding: 0;
border-left: 2px solid #e9ecef;
padding-left: 0.8rem;
}
.toc-link {
display: block;
padding: 0.3rem 0.5rem;
color: #6c757d;
text-decoration: none;
border-radius: 4px;
transition: all 0.2s ease;
position: relative;
}
.toc-link:hover {
color: #495057;
background-color: #e9ecef;
text-decoration: none;
}
.toc-link.active {
color: #007bff;
background-color: rgba(0, 123, 255, 0.1);
font-weight: 500;
}
.toc-link.active::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 3px;
height: 1.2em;
background-color: #007bff;
border-radius: 2px;
}
/* Level-specific styling */
.toc-level-1 {
font-weight: 600;
font-size: 1rem;
}
.toc-level-2 {
font-weight: 500;
font-size: 0.95rem;
}
.toc-level-3 {
font-weight: normal;
font-size: 0.9rem;
}
.toc-level-4,
.toc-level-5,
.toc-level-6 {
font-weight: normal;
font-size: 0.85rem;
opacity: 0.8;
}
/* Sticky TOC for larger screens */
@media (min-width: 1200px) {
.table-of-contents.sticky {
position: sticky;
top: 2rem;
float: right;
width: 280px;
margin-left: 2rem;
margin-bottom: 2rem;
max-height: calc(100vh - 4rem);
overflow-y: auto;
}
}
/* Heading anchor links */
h1, h2, h3, h4, h5, h6 {
position: relative;
scroll-margin-top: 80px; /* Account for fixed headers */
}
.heading-anchor {
opacity: 0;
margin-left: 0.5rem;
color: #6c757d;
text-decoration: none;
font-weight: normal;
transition: opacity 0.2s ease;
}
h1:hover .heading-anchor,
h2:hover .heading-anchor,
h3:hover .heading-anchor,
h4:hover .heading-anchor,
h5:hover .heading-anchor,
h6:hover .heading-anchor,
.heading-anchor:focus {
opacity: 1;
}
.heading-anchor::before {
content: '🔗';
font-size: 0.8em;
}
/* Alternative text-based anchor */
.heading-anchor.text-anchor::before {
content: '#';
font-family: monospace;
font-size: 0.9em;
}
/* Active heading highlighting */
h1.active,
h2.active,
h3.active,
h4.active,
h5.active,
h6.active {
color: #007bff;
position: relative;
}
h1.active::before,
h2.active::before,
h3.active::before,
h4.active::before,
h5.active::before,
h6.active::before {
content: '';
position: absolute;
left: -1rem;
top: 0;
bottom: 0;
width: 4px;
background-color: #007bff;
border-radius: 2px;
}
/* Smooth scroll behavior */
html {
scroll-behavior: smooth;
}
/* Override smooth scroll for users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
}
/* In-page navigation buttons */
.nav-button {
display: inline-block;
padding: 0.5rem 1rem;
background: #007bff;
color: white;
text-decoration: none;
border-radius: 4px;
font-size: 0.9rem;
transition: background-color 0.2s ease;
margin: 0.25rem 0.5rem 0.25rem 0;
}
.nav-button:hover {
background: #0056b3;
text-decoration: none;
color: white;
}
.nav-button.secondary {
background: #6c757d;
}
.nav-button.secondary:hover {
background: #545b62;
}
/* Breadcrumb navigation */
.breadcrumb-nav {
background: #f8f9fa;
padding: 0.75rem 1rem;
margin: 1rem 0;
border-radius: 4px;
font-size: 0.9rem;
border-left: 4px solid #007bff;
}
.breadcrumb-nav ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
align-items: center;
}
.breadcrumb-nav li {
margin: 0;
padding: 0;
}
.breadcrumb-nav li:not(:last-child)::after {
content: '→';
margin: 0 0.5rem;
color: #6c757d;
}
.breadcrumb-nav a {
color: #007bff;
text-decoration: none;
}
.breadcrumb-nav a:hover {
text-decoration: underline;
}
/* Skip to content link for accessibility */
.skip-to-content {
position: absolute;
top: -40px;
left: 6px;
background: #000;
color: white;
padding: 8px;
text-decoration: none;
z-index: 1000;
border-radius: 4px;
}
.skip-to-content:focus {
top: 6px;
}
/* Mobile responsive design */
@media (max-width: 768px) {
.table-of-contents {
margin: 1rem -1rem;
border-radius: 0;
border-left: none;
border-right: none;
}
.table-of-contents.sticky {
position: static;
float: none;
width: auto;
margin: 1rem 0;
}
.toc-list ul {
margin-left: 1rem;
padding-left: 0.6rem;
}
h1, h2, h3, h4, h5, h6 {
scroll-margin-top: 60px;
}
.breadcrumb-nav {
padding: 0.5rem;
margin: 0.5rem 0;
}
.breadcrumb-nav ul {
flex-direction: column;
align-items: flex-start;
}
.breadcrumb-nav li:not(:last-child)::after {
display: none;
}
}
/* Print styles */
@media print {
.table-of-contents {
page-break-inside: avoid;
background: white;
border: 1px solid #000;
}
.heading-anchor {
display: none;
}
.nav-button {
display: none;
}
a[href^="#"]::after {
content: " (see page " target-counter(attr(href), page) ")";
font-size: 0.8em;
color: #666;
}
}
/* High contrast mode support */
@media (prefers-contrast: high) {
.table-of-contents {
border: 2px solid;
background: white;
}
.toc-link.active {
background-color: highlight;
color: highlighttext;
}
}
/* Focus indicators for keyboard navigation */
.toc-link:focus,
.nav-button:focus,
.heading-anchor:focus {
outline: 2px solid #007bff;
outline-offset: 2px;
}
/* Loading state for dynamic TOC */
.table-of-contents.loading {
opacity: 0.6;
pointer-events: none;
}
.table-of-contents.loading::after {
content: 'Loading table of contents...';
display: block;
text-align: center;
font-style: italic;
color: #6c757d;
margin-top: 1rem;
}
Cross-Platform Implementation Strategies
Jekyll Integration
Implementing anchor links in Jekyll with automatic heading processing:
<!-- _includes/table-of-contents.html - Jekyll TOC generation -->
{% assign toc_content = "" %}
{% assign headings = "" %}
{% assign heading_levels = "" %}
<!-- Extract headings from content -->
{% assign content_array = include.content | split: "<h" %}
{% for item in content_array %}
{% if forloop.first == false %}
{% assign heading_parts = item | split: ">" %}
{% assign level = heading_parts[0] | slice: 0, 1 %}
{% assign heading_content = heading_parts[1] | split: "</h" | first %}
{% if heading_content and level %}
<!-- Generate heading ID -->
{% assign heading_id = heading_content | strip_html | downcase | replace: " ", "-" | replace: "'", "" | replace: ":", "" | replace: ".", "" | replace: ",", "" | replace: "!", "" | replace: "?", "" %}
<!-- Store heading data -->
{% assign headings = headings | append: heading_id | append: "|" | append: heading_content | append: "|" | append: level | append: "||" %}
{% endif %}
{% endif %}
{% endfor %}
<!-- Generate TOC structure -->
{% assign heading_array = headings | split: "||" %}
{% assign toc_html = "" %}
{% assign current_level = 0 %}
{% assign level_stack = "" %}
<div class="table-of-contents">
<h3>Table of Contents</h3>
<nav class="toc-nav">
<ul class="toc-list">
{% for heading_data in heading_array %}
{% if heading_data != "" %}
{% assign heading_parts = heading_data | split: "|" %}
{% assign h_id = heading_parts[0] %}
{% assign h_text = heading_parts[1] %}
{% assign h_level = heading_parts[2] | plus: 0 %}
{% if h_level > current_level %}
<!-- Open nested lists -->
{% for i in (current_level..h_level) %}
{% if forloop.first == false %}
<li><ul>
{% endif %}
{% endfor %}
{% elsif h_level < current_level %}
<!-- Close nested lists -->
{% assign levels_to_close = current_level | minus: h_level %}
{% for i in (1..levels_to_close) %}
</ul></li>
{% endfor %}
</li>
{% elsif current_level > 0 %}
</li>
{% endif %}
<li>
<a href="#{{ h_id }}" class="toc-link toc-level-{{ h_level }}">
{{ h_text | strip_html }}
</a>
{% assign current_level = h_level %}
{% endif %}
{% endfor %}
<!-- Close remaining open tags -->
</li>
{% for i in (2..current_level) %}
</ul></li>
{% endfor %}
</ul>
</nav>
</div>
<!-- Auto-inject heading anchors -->
<script>
document.addEventListener('DOMContentLoaded', function() {
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
headings.forEach(heading => {
if (heading.id) {
const anchor = document.createElement('a');
anchor.href = '#' + heading.id;
anchor.className = 'heading-anchor';
anchor.setAttribute('aria-label', 'Link to ' + heading.textContent);
anchor.innerHTML = '<span aria-hidden="true">#</span>';
heading.appendChild(anchor);
}
});
});
</script>
Hugo Implementation
Advanced anchor link processing for Hugo static sites:
<!-- layouts/partials/table-of-contents.html -->
<div class="table-of-contents">
<h3></h3>
<nav class="toc-nav">
</nav>
</div>
<!-- layouts/partials/heading-anchors.html -->
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
<header class="post-header">
<h1 class="post-title p-name" itemprop="name headline">Markdown Custom Directives and Block Extensions: Complete Guide to Advanced Content Blocks and Interactive Components</h1>
<p class="post-meta"><time class="dt-published" datetime="2025-12-30T00:00:00+00:00" itemprop="datePublished">
Dec 30, 2025
</time>•
<span itemprop="author" itemscope itemtype="http://schema.org/Person">
<span class="p-author h-card" itemprop="name">Matthew Rathbone</span></span></p>
</header>
<div class="post-content e-content" itemprop="articleBody">
<p>Custom Markdown directives and block extensions enable sophisticated content creation through extensible syntax systems, interactive components, and advanced formatting capabilities that extend beyond standard Markdown limitations. By implementing custom directive processors, developing reusable content blocks, and creating sophisticated extension systems, technical writers and developers can build powerful documentation platforms that combine Markdown’s simplicity with the flexibility of custom content components and interactive elements.</p>
<h2 id="why-use-custom-directives-and-block-extensions">Why Use Custom Directives and Block Extensions?</h2>
<p>Advanced Markdown extensibility provides essential capabilities for modern content systems:</p>
<ul>
<li><strong>Enhanced Content Components</strong>: Create reusable, interactive content blocks beyond basic Markdown</li>
<li><strong>Custom Syntax Systems</strong>: Develop domain-specific markup languages for specialized content types</li>
<li><strong>Interactive Documentation</strong>: Build dynamic content with embedded functionality and user interactions</li>
<li><strong>Content Management Integration</strong>: Connect Markdown with external data sources and content management systems</li>
<li><strong>Platform Consistency</strong>: Ensure consistent styling and behavior across different content platforms</li>
</ul>
<h2 id="foundation-directive-systems">Foundation Directive Systems</h2>
<h3 id="basic-directive-syntax-patterns">Basic Directive Syntax Patterns</h3>
<p>Common approaches to custom directive implementation:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># Standard Directive Patterns</span>
<span class="gu">## Block Directive Syntax</span>
:::info
This is an information block with custom styling and behavior.
:::
:::warning title="Important Notice"
This is a warning block with a custom title parameter.
:::
:::code-example language="javascript" filename="example.js"
<span class="p">```</span><span class="nl">javascript
</span><span class="kd">function</span> <span class="nf">customDirective</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">Custom directive content</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">```</span>
::::
<span class="gu">## Inline Directive Syntax</span>
This paragraph contains an inline {%note%}important note{%/note%} directive.
Use {%badge color="primary"%}Custom Badge{%/badge%} for highlighting.
Insert {%icon name="warning"%} for contextual icons.
<span class="gu">## Parameterized Directives</span>
:::tab-group
:::tab title="JavaScript"
<span class="p">```</span><span class="nl">javascript
</span><span class="c1">// JavaScript implementation</span>
<span class="p">```</span>
:::
:::tab title="Python"
<span class="p">```</span><span class="nl">python
</span><span class="c1"># Python implementation</span>
<span class="p">```</span>
:::
:::
<span class="gu">## Content-Rich Directives</span>
:::definition term="API Gateway"
An API Gateway is a server that acts as an API front-end, receiving API requests, enforcing throttling and security policies, passing requests to the back-end service, and then passing the response back to the requester.
<span class="gs">**Key Features:**</span>
<span class="p">-</span> Request routing and composition
<span class="p">-</span> Authentication and authorization
<span class="p">-</span> Rate limiting and throttling
<span class="p">-</span> Request and response transformation
:::
:::example
<span class="gs">**Problem**</span>: How to implement user authentication?
<span class="gs">**Solution**</span>: Use JSON Web Tokens (JWT) for stateless authentication.
<span class="p">```</span><span class="nl">javascript
</span><span class="kd">const</span> <span class="nx">jwt</span> <span class="o">=</span> <span class="nf">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">jsonwebtoken</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">function</span> <span class="nf">generateToken</span><span class="p">(</span><span class="nx">user</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">jwt</span><span class="p">.</span><span class="nf">sign</span><span class="p">(</span>
<span class="p">{</span> <span class="na">id</span><span class="p">:</span> <span class="nx">user</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span> <span class="na">email</span><span class="p">:</span> <span class="nx">user</span><span class="p">.</span><span class="nx">email</span> <span class="p">},</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">JWT_SECRET</span><span class="p">,</span>
<span class="p">{</span> <span class="na">expiresIn</span><span class="p">:</span> <span class="dl">'</span><span class="s1">1h</span><span class="dl">'</span> <span class="p">}</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="p">```</span>
<span class="gs">**Explanation**</span>: This creates a secure token that can be verified without server-side session storage.
:::
</code></pre></div></div>
<h3 id="advanced-directive-processors">Advanced Directive Processors</h3>
<p>Creating sophisticated directive processing systems:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// markdown-directive-processor.js - Comprehensive directive processing system</span>
<span class="kd">class</span> <span class="nc">MarkdownDirectiveProcessor</span> <span class="p">{</span>
<span class="nf">constructor</span><span class="p">(</span><span class="nx">options</span> <span class="o">=</span> <span class="p">{})</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">allowCustomHTML</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
<span class="na">validateDirectives</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">customDirectives</span><span class="p">:</span> <span class="k">new</span> <span class="nc">Map</span><span class="p">(),</span>
<span class="na">templateEngine</span><span class="p">:</span> <span class="dl">'</span><span class="s1">default</span><span class="dl">'</span><span class="p">,</span>
<span class="na">securityLevel</span><span class="p">:</span> <span class="dl">'</span><span class="s1">strict</span><span class="dl">'</span><span class="p">,</span>
<span class="p">...</span><span class="nx">options</span>
<span class="p">};</span>
<span class="k">this</span><span class="p">.</span><span class="nx">directiveRegistry</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Map</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">templateCache</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Map</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">directivesProcessed</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="na">errors</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="na">warnings</span><span class="p">:</span> <span class="mi">0</span>
<span class="p">};</span>
<span class="k">this</span><span class="p">.</span><span class="nf">initializeBuiltinDirectives</span><span class="p">();</span>
<span class="p">}</span>
<span class="nf">initializeBuiltinDirectives</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// Register built-in directive types</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">info</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createInfoBlock</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">warning</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createWarningBlock</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">code-example</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createCodeExample</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">definition</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createDefinition</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">example</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createExample</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">tab-group</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createTabGroup</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">tab</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createTab</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">note</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createInlineNote</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">badge</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createBadge</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">icon</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createIcon</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="p">}</span>
<span class="nf">registerDirective</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">processor</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nx">processor</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">function</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="s2">`Directive processor for '</span><span class="p">${</span><span class="nx">name</span><span class="p">}</span><span class="s2">' must be a function`</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">directiveRegistry</span><span class="p">.</span><span class="nf">set</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="p">{</span>
<span class="nx">processor</span><span class="p">,</span>
<span class="na">registeredAt</span><span class="p">:</span> <span class="k">new</span> <span class="nc">Date</span><span class="p">(),</span>
<span class="na">usageCount</span><span class="p">:</span> <span class="mi">0</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="nf">processMarkdown</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="c1">// Process block directives first</span>
<span class="nx">content</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">processBlockDirectives</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="c1">// Then process inline directives</span>
<span class="nx">content</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">processInlineDirectives</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="c1">// Post-process for nested directives</span>
<span class="nx">content</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">processNestedDirectives</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">content</span><span class="p">;</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">errors</span><span class="o">++</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Directive processing error:</span><span class="dl">'</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">content</span><span class="p">;</span> <span class="c1">// Return original content on error</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nf">processBlockDirectives</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Pattern for block directives: :::directive-name params\ncontent\n:::</span>
<span class="kd">const</span> <span class="nx">blockDirectivePattern</span> <span class="o">=</span> <span class="sr">/:::</span><span class="se">(\w</span><span class="sr">+</span><span class="se">)(?:\s</span><span class="sr">+</span><span class="se">([^\n]</span><span class="sr">*</span><span class="se">))?\n([\s\S]</span><span class="sr">*</span><span class="se">?)\n</span><span class="sr">:::/g</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">content</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="nx">blockDirectivePattern</span><span class="p">,</span> <span class="p">(</span><span class="nx">match</span><span class="p">,</span> <span class="nx">directiveName</span><span class="p">,</span> <span class="nx">params</span><span class="p">,</span> <span class="nx">directiveContent</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">directivesProcessed</span><span class="o">++</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">directive</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">directiveRegistry</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="nx">directiveName</span><span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">directive</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">warnings</span><span class="o">++</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">warn</span><span class="p">(</span><span class="s2">`Unknown directive: </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nf">createErrorBlock</span><span class="p">(</span><span class="s2">`Unknown directive: </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">directive</span><span class="p">.</span><span class="nx">usageCount</span><span class="o">++</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">parsedParams</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseDirectiveParams</span><span class="p">(</span><span class="nx">params</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">context</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">name</span><span class="p">:</span> <span class="nx">directiveName</span><span class="p">,</span>
<span class="na">params</span><span class="p">:</span> <span class="nx">parsedParams</span><span class="p">,</span>
<span class="na">content</span><span class="p">:</span> <span class="nx">directiveContent</span><span class="p">.</span><span class="nf">trim</span><span class="p">(),</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">block</span><span class="dl">'</span>
<span class="p">};</span>
<span class="k">return</span> <span class="nx">directive</span><span class="p">.</span><span class="nf">processor</span><span class="p">(</span><span class="nx">context</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">errors</span><span class="o">++</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="s2">`Error processing directive </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">:`</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nf">createErrorBlock</span><span class="p">(</span><span class="s2">`Error in directive: </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="nf">processInlineDirectives</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Pattern for inline directives: {%directive-name params%}content{%/directive-name%}</span>
<span class="kd">const</span> <span class="nx">inlineDirectivePattern</span> <span class="o">=</span> <span class="sr">/</span><span class="se">\{</span><span class="sr">%</span><span class="se">(\w</span><span class="sr">+</span><span class="se">)(?:\s</span><span class="sr">+</span><span class="se">([^</span><span class="sr">%</span><span class="se">]</span><span class="sr">*</span><span class="se">))?\%\}(</span><span class="sr">.*</span><span class="se">?)\{</span><span class="sr">%</span><span class="se">\/\1\%\}</span><span class="sr">/g</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">content</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="nx">inlineDirectivePattern</span><span class="p">,</span> <span class="p">(</span><span class="nx">match</span><span class="p">,</span> <span class="nx">directiveName</span><span class="p">,</span> <span class="nx">params</span><span class="p">,</span> <span class="nx">directiveContent</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">directivesProcessed</span><span class="o">++</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">directive</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">directiveRegistry</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="nx">directiveName</span><span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">directive</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">warnings</span><span class="o">++</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">warn</span><span class="p">(</span><span class="s2">`Unknown inline directive: </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="k">return</span> <span class="s2">`<span class="directive-error">Unknown directive: </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2"></span>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">directive</span><span class="p">.</span><span class="nx">usageCount</span><span class="o">++</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">parsedParams</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseDirectiveParams</span><span class="p">(</span><span class="nx">params</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">context</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">name</span><span class="p">:</span> <span class="nx">directiveName</span><span class="p">,</span>
<span class="na">params</span><span class="p">:</span> <span class="nx">parsedParams</span><span class="p">,</span>
<span class="na">content</span><span class="p">:</span> <span class="nx">directiveContent</span><span class="p">.</span><span class="nf">trim</span><span class="p">(),</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">inline</span><span class="dl">'</span>
<span class="p">};</span>
<span class="k">return</span> <span class="nx">directive</span><span class="p">.</span><span class="nf">processor</span><span class="p">(</span><span class="nx">context</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">errors</span><span class="o">++</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="s2">`Error processing inline directive </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">:`</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
<span class="k">return</span> <span class="s2">`<span class="directive-error">Error in directive: </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2"></span>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="nf">processNestedDirectives</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Handle special cases like tab-group containers</span>
<span class="k">return</span> <span class="nx">content</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/:::tab-group</span><span class="se">\n([\s\S]</span><span class="sr">*</span><span class="se">?)\n</span><span class="sr">:::/g</span><span class="p">,</span> <span class="p">(</span><span class="nx">match</span><span class="p">,</span> <span class="nx">tabsContent</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">tabs</span> <span class="o">=</span> <span class="p">[];</span>
<span class="kd">const</span> <span class="nx">tabPattern</span> <span class="o">=</span> <span class="sr">/:::tab</span><span class="se">\s</span><span class="sr">+title="</span><span class="se">([^</span><span class="sr">"</span><span class="se">]</span><span class="sr">+</span><span class="se">)</span><span class="sr">"</span><span class="se">(?:\s</span><span class="sr">+</span><span class="se">([^\n]</span><span class="sr">*</span><span class="se">))?\n([\s\S]</span><span class="sr">*</span><span class="se">?)(?=</span><span class="sr">:::tab|$</span><span class="se">)</span><span class="sr">/g</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">tabMatch</span><span class="p">;</span>
<span class="k">while </span><span class="p">((</span><span class="nx">tabMatch</span> <span class="o">=</span> <span class="nx">tabPattern</span><span class="p">.</span><span class="nf">exec</span><span class="p">(</span><span class="nx">tabsContent</span><span class="p">))</span> <span class="o">!==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">tabs</span><span class="p">.</span><span class="nf">push</span><span class="p">({</span>
<span class="na">title</span><span class="p">:</span> <span class="nx">tabMatch</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
<span class="na">params</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseDirectiveParams</span><span class="p">(</span><span class="nx">tabMatch</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">||</span> <span class="dl">''</span><span class="p">),</span>
<span class="na">content</span><span class="p">:</span> <span class="nx">tabMatch</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="nf">trim</span><span class="p">()</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nf">createTabGroup</span><span class="p">({</span> <span class="na">content</span><span class="p">:</span> <span class="dl">''</span><span class="p">,</span> <span class="na">params</span><span class="p">:</span> <span class="p">{},</span> <span class="nx">tabs</span> <span class="p">});</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="nf">parseDirectiveParams</span><span class="p">(</span><span class="nx">paramString</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">paramString</span><span class="p">)</span> <span class="k">return</span> <span class="p">{};</span>
<span class="kd">const</span> <span class="nx">params</span> <span class="o">=</span> <span class="p">{};</span>
<span class="c1">// Handle quoted parameters: key="value"</span>
<span class="kd">const</span> <span class="nx">quotedParamPattern</span> <span class="o">=</span> <span class="sr">/</span><span class="se">(\w</span><span class="sr">+</span><span class="se">)</span><span class="sr">="</span><span class="se">([^</span><span class="sr">"</span><span class="se">]</span><span class="sr">*</span><span class="se">)</span><span class="sr">"/g</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">match</span><span class="p">;</span>
<span class="k">while </span><span class="p">((</span><span class="nx">match</span> <span class="o">=</span> <span class="nx">quotedParamPattern</span><span class="p">.</span><span class="nf">exec</span><span class="p">(</span><span class="nx">paramString</span><span class="p">))</span> <span class="o">!==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">params</span><span class="p">[</span><span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">=</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="p">}</span>
<span class="c1">// Handle unquoted parameters: key=value</span>
<span class="kd">const</span> <span class="nx">unquotedParamPattern</span> <span class="o">=</span> <span class="sr">/</span><span class="se">(\w</span><span class="sr">+</span><span class="se">)</span><span class="sr">=</span><span class="se">(\w</span><span class="sr">+</span><span class="se">)</span><span class="sr">/g</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">cleanedString</span> <span class="o">=</span> <span class="nx">paramString</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="nx">quotedParamPattern</span><span class="p">,</span> <span class="dl">''</span><span class="p">);</span>
<span class="k">while </span><span class="p">((</span><span class="nx">match</span> <span class="o">=</span> <span class="nx">unquotedParamPattern</span><span class="p">.</span><span class="nf">exec</span><span class="p">(</span><span class="nx">cleanedString</span><span class="p">))</span> <span class="o">!==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">params</span><span class="p">[</span><span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">=</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="p">}</span>
<span class="c1">// Handle boolean flags: just the parameter name</span>
<span class="kd">const</span> <span class="nx">remainingString</span> <span class="o">=</span> <span class="nx">cleanedString</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="nx">unquotedParamPattern</span><span class="p">,</span> <span class="dl">''</span><span class="p">).</span><span class="nf">trim</span><span class="p">();</span>
<span class="k">if </span><span class="p">(</span><span class="nx">remainingString</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">remainingString</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="sr">/</span><span class="se">\s</span><span class="sr">+/</span><span class="p">).</span><span class="nf">forEach</span><span class="p">(</span><span class="nx">flag</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="nx">flag</span> <span class="o">&&</span> <span class="o">!</span><span class="nx">params</span><span class="p">[</span><span class="nx">flag</span><span class="p">])</span> <span class="p">{</span>
<span class="nx">params</span><span class="p">[</span><span class="nx">flag</span><span class="p">]</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">params</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Built-in directive implementations</span>
<span class="nf">createInfoBlock</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">title</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">icon</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">icon</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">ℹ️</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<div class="directive-block directive-info">
</span><span class="p">${</span><span class="nx">title</span> <span class="p">?</span> <span class="s2">`<div class="directive-header">
<span class="directive-icon"></span><span class="p">${</span><span class="nx">icon</span><span class="p">}</span><span class="s2"></span>
<span class="directive-title"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">title</span><span class="p">)}</span><span class="s2"></span>
</div>`</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">
<div class="directive-content">
</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">processInnerContent</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2">
</div>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createWarningBlock</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">title</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">Warning</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">icon</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">icon</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">⚠️</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<div class="directive-block directive-warning">
<div class="directive-header">
<span class="directive-icon"></span><span class="p">${</span><span class="nx">icon</span><span class="p">}</span><span class="s2"></span>
<span class="directive-title"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">title</span><span class="p">)}</span><span class="s2"></span>
</div>
<div class="directive-content">
</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">processInnerContent</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2">
</div>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createCodeExample</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">language</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">language</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">text</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">filename</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">filename</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">highlight</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<div class="directive-block directive-code-example">
</span><span class="p">${</span><span class="nx">filename</span> <span class="p">?</span> <span class="s2">`<div class="code-filename"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">filename</span><span class="p">)}</span><span class="s2"></div>`</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">
<div class="code-container">
<pre class="code-block language-</span><span class="p">${</span><span class="nx">language</span><span class="p">}</span><span class="s2">"</span><span class="p">${</span><span class="nx">highlight</span> <span class="p">?</span> <span class="s2">` data-highlight="</span><span class="p">${</span><span class="nx">highlight</span><span class="p">}</span><span class="s2">"`</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">><code></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2"></code></pre>
</div>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createDefinition</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">term</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">term</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<div class="directive-block directive-definition">
<div class="definition-term"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">term</span><span class="p">)}</span><span class="s2"></div>
<div class="definition-content">
</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">processInnerContent</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2">
</div>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createExample</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">title</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">Example</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<div class="directive-block directive-example">
<div class="directive-header">
<span class="directive-icon">💡</span>
<span class="directive-title"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">title</span><span class="p">)}</span><span class="s2"></span>
</div>
<div class="directive-content">
</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">processInnerContent</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2">
</div>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createTabGroup</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">tabs</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">tabs</span> <span class="o">||</span> <span class="nx">tabs</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="dl">''</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">tabsId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="kd">let</span> <span class="nx">tabsHtml</span> <span class="o">=</span> <span class="s2">`<div class="directive-tabs" data-tabs-id="</span><span class="p">${</span><span class="nx">tabsId</span><span class="p">}</span><span class="s2">">`</span><span class="p">;</span>
<span class="c1">// Create tab headers</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1"><div class="tab-headers"></span><span class="dl">'</span><span class="p">;</span>
<span class="nx">tabs</span><span class="p">.</span><span class="nf">forEach</span><span class="p">((</span><span class="nx">tab</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">activeClass</span> <span class="o">=</span> <span class="nx">index</span> <span class="o">===</span> <span class="mi">0</span> <span class="p">?</span> <span class="dl">'</span><span class="s1"> active</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">''</span><span class="p">;</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="s2">`<button class="tab-header</span><span class="p">${</span><span class="nx">activeClass</span><span class="p">}</span><span class="s2">" data-tab="</span><span class="p">${</span><span class="nx">index</span><span class="p">}</span><span class="s2">"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">tab</span><span class="p">.</span><span class="nx">title</span><span class="p">)}</span><span class="s2"></button>`</span><span class="p">;</span>
<span class="p">});</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1"></div></span><span class="dl">'</span><span class="p">;</span>
<span class="c1">// Create tab content</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1"><div class="tab-contents"></span><span class="dl">'</span><span class="p">;</span>
<span class="nx">tabs</span><span class="p">.</span><span class="nf">forEach</span><span class="p">((</span><span class="nx">tab</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">activeClass</span> <span class="o">=</span> <span class="nx">index</span> <span class="o">===</span> <span class="mi">0</span> <span class="p">?</span> <span class="dl">'</span><span class="s1"> active</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">''</span><span class="p">;</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="s2">`<div class="tab-content</span><span class="p">${</span><span class="nx">activeClass</span><span class="p">}</span><span class="s2">" data-tab="</span><span class="p">${</span><span class="nx">index</span><span class="p">}</span><span class="s2">">
</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">processInnerContent</span><span class="p">(</span><span class="nx">tab</span><span class="p">.</span><span class="nx">content</span><span class="p">)}</span><span class="s2">
</div>`</span><span class="p">;</span>
<span class="p">});</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1"></div></span><span class="dl">'</span><span class="p">;</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1"></div></span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">tabsHtml</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createTab</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// This is handled by createTabGroup, but we need the method for registration</span>
<span class="k">return</span> <span class="dl">''</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createInlineNote</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">type</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">type</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">info</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`<span class="directive-inline directive-note directive-note-</span><span class="p">${</span><span class="nx">type</span><span class="p">}</span><span class="s2">"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2"></span>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createBadge</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">color</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">color</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">primary</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">size</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">size</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">normal</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`<span class="directive-badge badge-</span><span class="p">${</span><span class="nx">color</span><span class="p">}</span><span class="s2"> badge-</span><span class="p">${</span><span class="nx">size</span><span class="p">}</span><span class="s2">"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2"></span>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createIcon</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">name</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">name</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">size</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">size</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">name</span><span class="p">)</span> <span class="k">return</span> <span class="dl">''</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`<span class="directive-icon icon-</span><span class="p">${</span><span class="nx">name</span><span class="p">}${</span><span class="nx">size</span> <span class="p">?</span> <span class="s2">` icon-</span><span class="p">${</span><span class="nx">size</span><span class="p">}</span><span class="s2">`</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">" aria-hidden="true"></span>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createErrorBlock</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="s2">`
<div class="directive-error-block">
<strong>Directive Error:</strong> </span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">message</span><span class="p">)}</span><span class="s2">
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">processInnerContent</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Process Markdown within directive content</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="k">this</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">markdownProcessor</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">function</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nf">markdownProcessor</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Basic markdown processing for common cases</span>
<span class="k">return</span> <span class="nx">content</span>
<span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/</span><span class="se">\*\*(</span><span class="sr">.*</span><span class="se">?)\*\*</span><span class="sr">/g</span><span class="p">,</span> <span class="dl">'</span><span class="s1"><strong>$1</strong></span><span class="dl">'</span><span class="p">)</span>
<span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/</span><span class="se">\*(</span><span class="sr">.*</span><span class="se">?)\*</span><span class="sr">/g</span><span class="p">,</span> <span class="dl">'</span><span class="s1"><em>$1</em></span><span class="dl">'</span><span class="p">)</span>
<span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/`</span><span class="se">(</span><span class="sr">.*</span><span class="se">?)</span><span class="sr">`/g</span><span class="p">,</span> <span class="dl">'</span><span class="s1"><code>$1</code></span><span class="dl">'</span><span class="p">)</span>
<span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/</span><span class="se">\n\n</span><span class="sr">/g</span><span class="p">,</span> <span class="dl">'</span><span class="s1"></p><p></span><span class="dl">'</span><span class="p">)</span>
<span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/^</span><span class="se">(?!</span><span class="sr"><p></span><span class="se">)</span><span class="sr">/</span><span class="p">,</span> <span class="dl">'</span><span class="s1"><p></span><span class="dl">'</span><span class="p">)</span>
<span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/</span><span class="se">(?<</span><span class="sr">!<</span><span class="se">\/</span><span class="sr">p></span><span class="se">)</span><span class="sr">$/</span><span class="p">,</span> <span class="dl">'</span><span class="s1"></p></span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">div</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="dl">'</span><span class="s1">div</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">div</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="nx">text</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">div</span><span class="p">.</span><span class="nx">innerHTML</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">generateId</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">random</span><span class="p">().</span><span class="nf">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nf">substr</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">getStats</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span>
<span class="p">...</span><span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">,</span>
<span class="na">registeredDirectives</span><span class="p">:</span> <span class="nb">Array</span><span class="p">.</span><span class="k">from</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">directiveRegistry</span><span class="p">.</span><span class="nf">keys</span><span class="p">()),</span>
<span class="na">directiveUsage</span><span class="p">:</span> <span class="nb">Array</span><span class="p">.</span><span class="k">from</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">directiveRegistry</span><span class="p">.</span><span class="nf">entries</span><span class="p">()).</span><span class="nf">map</span><span class="p">(([</span><span class="nx">name</span><span class="p">,</span> <span class="nx">data</span><span class="p">])</span> <span class="o">=></span> <span class="p">({</span>
<span class="nx">name</span><span class="p">,</span>
<span class="na">usageCount</span><span class="p">:</span> <span class="nx">data</span><span class="p">.</span><span class="nx">usageCount</span>
<span class="p">}))</span>
<span class="p">};</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Initialize directive processor</span>
<span class="kd">const</span> <span class="nx">directiveProcessor</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MarkdownDirectiveProcessor</span><span class="p">();</span>
<span class="c1">// CSS for directive styling</span>
<span class="kd">const</span> <span class="nx">directiveStyles</span> <span class="o">=</span> <span class="s2">`
/* Directive Block Styles */
.directive-block {
margin: 1.5rem 0;
border-radius: 0.375rem;
overflow: hidden;
}
.directive-info {
background: #e3f2fd;
border-left: 4px solid #2196f3;
}
.directive-warning {
background: #fff3cd;
border-left: 4px solid #ff9800;
}
.directive-example {
background: #f0f9ff;
border-left: 4px solid #0ea5e9;
}
.directive-definition {
background: #f8f9fa;
border: 1px solid #dee2e6;
}
.directive-header {
display: flex;
align-items: center;
padding: 0.75rem 1rem;
background: rgba(0,0,0,0.05);
font-weight: 600;
}
.directive-icon {
margin-right: 0.5rem;
font-size: 1.1em;
}
.directive-content {
padding: 1rem;
}
.directive-content p:last-child {
margin-bottom: 0;
}
/* Code Example Styles */
.directive-code-example {
background: #f8f9fa;
border: 1px solid #dee2e6;
}
.code-filename {
background: #495057;
color: white;
padding: 0.5rem 1rem;
font-family: monospace;
font-size: 0.9rem;
}
.code-container {
overflow-x: auto;
}
.code-block {
margin: 0;
padding: 1rem;
background: #f8f9fa;
border: none;
font-family: 'Courier New', monospace;
line-height: 1.5;
}
/* Tab Styles */
.directive-tabs {
border: 1px solid #dee2e6;
border-radius: 0.375rem;
overflow: hidden;
}
.tab-headers {
display: flex;
background: #f8f9fa;
border-bottom: 1px solid #dee2e6;
}
.tab-header {
background: none;
border: none;
padding: 0.75rem 1rem;
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.2s ease;
}
.tab-header:hover {
background: #e9ecef;
}
.tab-header.active {
background: white;
border-bottom-color: #007cba;
color: #007cba;
font-weight: 600;
}
.tab-contents {
position: relative;
}
.tab-content {
display: none;
padding: 1rem;
}
.tab-content.active {
display: block;
}
/* Inline Directive Styles */
.directive-inline {
display: inline;
}
.directive-note {
padding: 0.2rem 0.4rem;
border-radius: 0.25rem;
font-size: 0.9rem;
}
.directive-note-info {
background: #cfe2ff;
color: #084298;
}
.directive-note-warning {
background: #fff3cd;
color: #664d03;
}
.directive-badge {
display: inline-block;
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
font-weight: 600;
line-height: 1;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: 0.375rem;
}
.badge-primary {
color: white;
background-color: #007cba;
}
.badge-success {
color: white;
background-color: #28a745;
}
.badge-warning {
color: #212529;
background-color: #ffc107;
}
.badge-danger {
color: white;
background-color: #dc3545;
}
.badge-small {
padding: 0.125rem 0.375rem;
font-size: 0.75rem;
}
.badge-large {
padding: 0.375rem 0.75rem;
font-size: 1rem;
}
/* Definition Styles */
.definition-term {
font-weight: 700;
font-size: 1.1em;
color: #495057;
margin-bottom: 0.5rem;
}
.definition-content {
color: #6c757d;
}
/* Error Styles */
.directive-error-block {
background: #f8d7da;
color: #721c24;
padding: 1rem;
border: 1px solid #f5c6cb;
border-radius: 0.375rem;
margin: 1rem 0;
}
.directive-error {
color: #dc3545;
font-style: italic;
}
/* Responsive Design */
@media (max-width: 768px) {
.directive-block {
margin: 1rem 0;
}
.directive-header,
.directive-content {
padding: 0.75rem;
}
.tab-headers {
flex-wrap: wrap;
}
.tab-header {
min-width: 0;
flex: 1;
}
}
`</span><span class="p">;</span>
<span class="c1">// JavaScript for interactive functionality</span>
<span class="kd">const</span> <span class="nx">directiveInteractions</span> <span class="o">=</span> <span class="s2">`
// Tab functionality
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.directive-tabs').forEach(tabGroup => {
const headers = tabGroup.querySelectorAll('.tab-header');
const contents = tabGroup.querySelectorAll('.tab-content');
headers.forEach(header => {
header.addEventListener('click', () => {
const tabIndex = header.getAttribute('data-tab');
// Remove active class from all headers and contents
headers.forEach(h => h.classList.remove('active'));
contents.forEach(c => c.classList.remove('active'));
// Add active class to clicked header and corresponding content
header.classList.add('active');
const activeContent = tabGroup.querySelector(</span><span class="se">\`</span><span class="s2">[data-tab="</span><span class="se">\$</span><span class="s2">{tabIndex}"].tab-content</span><span class="se">\`</span><span class="s2">);
if (activeContent) {
activeContent.classList.add('active');
}
});
});
});
});
`</span><span class="p">;</span>
<span class="c1">// Inject styles and scripts</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nb">document</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">undefined</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">style</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="dl">'</span><span class="s1">style</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">style</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="nx">directiveStyles</span><span class="p">;</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nf">appendChild</span><span class="p">(</span><span class="nx">style</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">script</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="dl">'</span><span class="s1">script</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="nx">directiveInteractions</span><span class="p">;</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nf">appendChild</span><span class="p">(</span><span class="nx">script</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="advanced-extension-systems">Advanced Extension Systems</h2>
<h3 id="plugin-architecture-for-directives">Plugin Architecture for Directives</h3>
<p>Create modular, extensible directive systems:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// markdown-directive-plugin-system.js</span>
<span class="kd">class</span> <span class="nc">MarkdownDirectivePluginSystem</span> <span class="p">{</span>
<span class="nf">constructor</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">plugins</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Map</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">hooks</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">beforeProcessing</span><span class="p">:</span> <span class="p">[],</span>
<span class="na">afterProcessing</span><span class="p">:</span> <span class="p">[],</span>
<span class="na">onDirectiveRegistered</span><span class="p">:</span> <span class="p">[],</span>
<span class="na">onDirectiveProcessed</span><span class="p">:</span> <span class="p">[],</span>
<span class="na">onError</span><span class="p">:</span> <span class="p">[]</span>
<span class="p">};</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processor</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">config</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">debug</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
<span class="na">strictMode</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">allowDynamicRegistration</span><span class="p">:</span> <span class="kc">true</span>
<span class="p">};</span>
<span class="p">}</span>
<span class="nf">registerPlugin</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">plugin</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">plugins</span><span class="p">.</span><span class="nf">has</span><span class="p">(</span><span class="nx">name</span><span class="p">))</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="s2">`Plugin '</span><span class="p">${</span><span class="nx">name</span><span class="p">}</span><span class="s2">' is already registered`</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Validate plugin structure</span>
<span class="k">this</span><span class="p">.</span><span class="nf">validatePlugin</span><span class="p">(</span><span class="nx">plugin</span><span class="p">);</span>
<span class="c1">// Initialize plugin</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nx">plugin</span><span class="p">.</span><span class="nx">init</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">function</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">plugin</span><span class="p">.</span><span class="nf">init</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Register plugin directives</span>
<span class="k">if </span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">directives</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">Object</span><span class="p">.</span><span class="nf">entries</span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">directives</span><span class="p">).</span><span class="nf">forEach</span><span class="p">(([</span><span class="nx">directiveName</span><span class="p">,</span> <span class="nx">processor</span><span class="p">])</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="s2">`</span><span class="p">${</span><span class="nx">name</span><span class="p">}</span><span class="s2">:</span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">`</span><span class="p">,</span> <span class="nx">processor</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="c1">// Register plugin hooks</span>
<span class="k">if </span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">hooks</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">Object</span><span class="p">.</span><span class="nf">entries</span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">hooks</span><span class="p">).</span><span class="nf">forEach</span><span class="p">(([</span><span class="nx">hookName</span><span class="p">,</span> <span class="nx">handler</span><span class="p">])</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">addHook</span><span class="p">(</span><span class="nx">hookName</span><span class="p">,</span> <span class="nx">handler</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">plugins</span><span class="p">.</span><span class="nf">set</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">plugin</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nf">emit</span><span class="p">(</span><span class="dl">'</span><span class="s1">onDirectiveRegistered</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">plugin</span> <span class="p">});</span>
<span class="p">}</span>
<span class="nf">validatePlugin</span><span class="p">(</span><span class="nx">plugin</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nx">plugin</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">object</span><span class="dl">'</span> <span class="o">||</span> <span class="nx">plugin</span> <span class="o">===</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Plugin must be an object</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">name</span> <span class="o">||</span> <span class="k">typeof</span> <span class="nx">plugin</span><span class="p">.</span><span class="nx">name</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Plugin must have a name property</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">version</span> <span class="o">||</span> <span class="k">typeof</span> <span class="nx">plugin</span><span class="p">.</span><span class="nx">version</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Plugin must have a version property</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if </span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">directives</span> <span class="o">&&</span> <span class="k">typeof</span> <span class="nx">plugin</span><span class="p">.</span><span class="nx">directives</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">object</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Plugin directives must be an object</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nf">registerDirective</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">processor</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">processor</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processor</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MarkdownDirectiveProcessor</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processor</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">processor</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">addHook</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">handler</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">hooks</span><span class="p">[</span><span class="nx">name</span><span class="p">])</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">hooks</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="p">[];</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">hooks</span><span class="p">[</span><span class="nx">name</span><span class="p">].</span><span class="nf">push</span><span class="p">(</span><span class="nx">handler</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">emit</span><span class="p">(</span><span class="nx">hookName</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">hooks</span><span class="p">[</span><span class="nx">hookName</span><span class="p">])</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">hooks</span><span class="p">[</span><span class="nx">hookName</span><span class="p">].</span><span class="nf">forEach</span><span class="p">(</span><span class="nx">handler</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="nf">handler</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="s2">`Error in hook </span><span class="p">${</span><span class="nx">hookName</span><span class="p">}</span><span class="s2">:`</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nf">processMarkdown</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">emit</span><span class="p">(</span><span class="dl">'</span><span class="s1">beforeProcessing</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="nx">content</span> <span class="p">});</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">processor</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processor</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MarkdownDirectiveProcessor</span><span class="p">();</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">processor</span><span class="p">.</span><span class="nf">processMarkdown</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nf">emit</span><span class="p">(</span><span class="dl">'</span><span class="s1">afterProcessing</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">result</span> <span class="p">});</span>
<span class="k">return</span> <span class="nx">result</span><span class="p">;</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">emit</span><span class="p">(</span><span class="dl">'</span><span class="s1">onError</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="nx">error</span><span class="p">,</span> <span class="nx">content</span> <span class="p">});</span>
<span class="k">throw</span> <span class="nx">error</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nf">getPlugin</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">plugins</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">listPlugins</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="nb">Array</span><span class="p">.</span><span class="k">from</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">plugins</span><span class="p">.</span><span class="nf">keys</span><span class="p">());</span>
<span class="p">}</span>
<span class="nf">unregisterPlugin</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">plugin</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">plugins</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="nx">plugin</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Call plugin cleanup if available</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nx">plugin</span><span class="p">.</span><span class="nx">cleanup</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">function</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">plugin</span><span class="p">.</span><span class="nf">cleanup</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Remove plugin directives</span>
<span class="k">if </span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">directives</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">Object</span><span class="p">.</span><span class="nf">keys</span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">directives</span><span class="p">).</span><span class="nf">forEach</span><span class="p">(</span><span class="nx">directiveName</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Remove from processor if available</span>
<span class="k">if </span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">processor</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processor</span><span class="p">.</span><span class="nx">directiveRegistry</span><span class="p">.</span><span class="k">delete</span><span class="p">(</span><span class="s2">`</span><span class="p">${</span><span class="nx">name</span><span class="p">}</span><span class="s2">:</span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">plugins</span><span class="p">.</span><span class="k">delete</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
<span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Example plugins</span>
<span class="kd">const</span> <span class="nx">chartPlugin</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">charts</span><span class="dl">'</span><span class="p">,</span>
<span class="na">version</span><span class="p">:</span> <span class="dl">'</span><span class="s1">1.0.0</span><span class="dl">'</span><span class="p">,</span>
<span class="na">description</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Adds chart generation directives</span><span class="dl">'</span><span class="p">,</span>
<span class="na">directives</span><span class="p">:</span> <span class="p">{</span>
<span class="dl">'</span><span class="s1">bar-chart</span><span class="dl">'</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseChartData</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">chartId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="k">return</span> <span class="s2">`
<div class="chart-container">
<canvas id="</span><span class="p">${</span><span class="nx">chartId</span><span class="p">}</span><span class="s2">" data-chart-type="bar" data-chart-data='</span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">data</span><span class="p">)}</span><span class="s2">' data-chart-options='</span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">params</span><span class="p">)}</span><span class="s2">'></canvas>
</div>`</span><span class="p">;</span>
<span class="p">},</span>
<span class="dl">'</span><span class="s1">line-chart</span><span class="dl">'</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseChartData</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">chartId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="k">return</span> <span class="s2">`
<div class="chart-container">
<canvas id="</span><span class="p">${</span><span class="nx">chartId</span><span class="p">}</span><span class="s2">" data-chart-type="line" data-chart-data='</span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">data</span><span class="p">)}</span><span class="s2">' data-chart-options='</span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">params</span><span class="p">)}</span><span class="s2">'></canvas>
</div>`</span><span class="p">;</span>
<span class="p">},</span>
<span class="dl">'</span><span class="s1">pie-chart</span><span class="dl">'</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseChartData</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">chartId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="k">return</span> <span class="s2">`
<div class="chart-container">
<canvas id="</span><span class="p">${</span><span class="nx">chartId</span><span class="p">}</span><span class="s2">" data-chart-type="pie" data-chart-data='</span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">data</span><span class="p">)}</span><span class="s2">' data-chart-options='</span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">params</span><span class="p">)}</span><span class="s2">'></canvas>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">parseChartData</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Parse CSV-like data from content</span>
<span class="kd">const</span> <span class="nx">lines</span> <span class="o">=</span> <span class="nx">content</span><span class="p">.</span><span class="nf">trim</span><span class="p">().</span><span class="nf">split</span><span class="p">(</span><span class="dl">'</span><span class="se">\n</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">headers</span> <span class="o">=</span> <span class="nx">lines</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nf">split</span><span class="p">(</span><span class="dl">'</span><span class="s1">,</span><span class="dl">'</span><span class="p">).</span><span class="nf">map</span><span class="p">(</span><span class="nx">h</span> <span class="o">=></span> <span class="nx">h</span><span class="p">.</span><span class="nf">trim</span><span class="p">());</span>
<span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">lines</span><span class="p">.</span><span class="nf">slice</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nf">map</span><span class="p">(</span><span class="nx">line</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">values</span> <span class="o">=</span> <span class="nx">line</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="dl">'</span><span class="s1">,</span><span class="dl">'</span><span class="p">).</span><span class="nf">map</span><span class="p">(</span><span class="nx">v</span> <span class="o">=></span> <span class="nx">v</span><span class="p">.</span><span class="nf">trim</span><span class="p">());</span>
<span class="kd">const</span> <span class="nx">row</span> <span class="o">=</span> <span class="p">{};</span>
<span class="nx">headers</span><span class="p">.</span><span class="nf">forEach</span><span class="p">((</span><span class="nx">header</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">row</span><span class="p">[</span><span class="nx">header</span><span class="p">]</span> <span class="o">=</span> <span class="nf">isNaN</span><span class="p">(</span><span class="nx">values</span><span class="p">[</span><span class="nx">index</span><span class="p">])</span> <span class="p">?</span> <span class="nx">values</span><span class="p">[</span><span class="nx">index</span><span class="p">]</span> <span class="p">:</span> <span class="nf">parseFloat</span><span class="p">(</span><span class="nx">values</span><span class="p">[</span><span class="nx">index</span><span class="p">]);</span>
<span class="p">});</span>
<span class="k">return</span> <span class="nx">row</span><span class="p">;</span>
<span class="p">});</span>
<span class="k">return</span> <span class="p">{</span>
<span class="nx">headers</span><span class="p">,</span>
<span class="nx">data</span>
<span class="p">};</span>
<span class="p">},</span>
<span class="na">generateId</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="dl">'</span><span class="s1">chart-</span><span class="dl">'</span> <span class="o">+</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">random</span><span class="p">().</span><span class="nf">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nf">substr</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">);</span>
<span class="p">},</span>
<span class="na">init</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">system</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Chart plugin initialized</span><span class="dl">'</span><span class="p">);</span>
<span class="c1">// Load Chart.js if not already loaded</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nx">Chart</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">undefined</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">loadChartJS</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">loadChartJS</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">script</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="dl">'</span><span class="s1">script</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">https://cdn.jsdelivr.net/npm/chart.js</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">onload</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Initialize charts after Chart.js loads</span>
<span class="k">this</span><span class="p">.</span><span class="nf">initializeCharts</span><span class="p">();</span>
<span class="p">};</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nf">appendChild</span><span class="p">(</span><span class="nx">script</span><span class="p">);</span>
<span class="p">},</span>
<span class="na">initializeCharts</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nb">document</span><span class="p">.</span><span class="nf">querySelectorAll</span><span class="p">(</span><span class="dl">'</span><span class="s1">[data-chart-type]</span><span class="dl">'</span><span class="p">).</span><span class="nf">forEach</span><span class="p">(</span><span class="nx">canvas</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">chartType</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nf">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-chart-type</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">chartData</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nf">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-chart-data</span><span class="dl">'</span><span class="p">));</span>
<span class="kd">const</span> <span class="nx">chartOptions</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nf">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-chart-options</span><span class="dl">'</span><span class="p">)</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">{}</span><span class="dl">'</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nf">renderChart</span><span class="p">(</span><span class="nx">canvas</span><span class="p">,</span> <span class="nx">chartType</span><span class="p">,</span> <span class="nx">chartData</span><span class="p">,</span> <span class="nx">chartOptions</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="na">renderChart</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">canvas</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">data</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">ctx</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nf">getContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">2d</span><span class="dl">'</span><span class="p">);</span>
<span class="c1">// Convert data format for Chart.js</span>
<span class="kd">const</span> <span class="nx">chartData</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">labels</span><span class="p">:</span> <span class="nx">data</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="nx">row</span> <span class="o">=></span> <span class="nx">row</span><span class="p">[</span><span class="nx">data</span><span class="p">.</span><span class="nx">headers</span><span class="p">[</span><span class="mi">0</span><span class="p">]]),</span>
<span class="na">datasets</span><span class="p">:</span> <span class="p">[{</span>
<span class="na">label</span><span class="p">:</span> <span class="nx">data</span><span class="p">.</span><span class="nx">headers</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">Data</span><span class="dl">'</span><span class="p">,</span>
<span class="na">data</span><span class="p">:</span> <span class="nx">data</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="nx">row</span> <span class="o">=></span> <span class="nx">row</span><span class="p">[</span><span class="nx">data</span><span class="p">.</span><span class="nx">headers</span><span class="p">[</span><span class="mi">1</span><span class="p">]]),</span>
<span class="na">backgroundColor</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateColors</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">length</span><span class="p">),</span>
<span class="na">borderColor</span><span class="p">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">borderColor</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">#007cba</span><span class="dl">'</span><span class="p">,</span>
<span class="na">borderWidth</span><span class="p">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">borderWidth</span> <span class="o">||</span> <span class="mi">1</span>
<span class="p">}]</span>
<span class="p">};</span>
<span class="k">new</span> <span class="nc">Chart</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> <span class="p">{</span>
<span class="na">type</span><span class="p">:</span> <span class="nx">type</span><span class="p">,</span>
<span class="na">data</span><span class="p">:</span> <span class="nx">chartData</span><span class="p">,</span>
<span class="na">options</span><span class="p">:</span> <span class="p">{</span>
<span class="na">responsive</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">plugins</span><span class="p">:</span> <span class="p">{</span>
<span class="na">title</span><span class="p">:</span> <span class="p">{</span>
<span class="na">display</span><span class="p">:</span> <span class="o">!!</span><span class="nx">options</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
<span class="na">text</span><span class="p">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">title</span> <span class="o">||</span> <span class="dl">''</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="p">...</span><span class="nx">options</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="na">generateColors</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">count</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">colors</span> <span class="o">=</span> <span class="p">[</span>
<span class="dl">'</span><span class="s1">#FF6384</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#36A2EB</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#FFCE56</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#4BC0C0</span><span class="dl">'</span><span class="p">,</span>
<span class="dl">'</span><span class="s1">#9966FF</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#FF9F40</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#FF6384</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#C9CBCF</span><span class="dl">'</span>
<span class="p">];</span>
<span class="k">return</span> <span class="nb">Array</span><span class="p">.</span><span class="k">from</span><span class="p">({</span><span class="na">length</span><span class="p">:</span> <span class="nx">count</span><span class="p">},</span> <span class="p">(</span><span class="nx">_</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span> <span class="nx">colors</span><span class="p">[</span><span class="nx">i</span> <span class="o">%</span> <span class="nx">colors</span><span class="p">.</span><span class="nx">length</span><span class="p">]);</span>
<span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">interactivePlugin</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">interactive</span><span class="dl">'</span><span class="p">,</span>
<span class="na">version</span><span class="p">:</span> <span class="dl">'</span><span class="s1">1.0.0</span><span class="dl">'</span><span class="p">,</span>
<span class="na">description</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Adds interactive content directives</span><span class="dl">'</span><span class="p">,</span>
<span class="na">directives</span><span class="p">:</span> <span class="p">{</span>
<span class="dl">'</span><span class="s1">accordion</span><span class="dl">'</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">accordionId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">items</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseAccordionItems</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">html</span> <span class="o">=</span> <span class="s2">`<div class="accordion" id="</span><span class="p">${</span><span class="nx">accordionId</span><span class="p">}</span><span class="s2">">`</span><span class="p">;</span>
<span class="nx">items</span><span class="p">.</span><span class="nf">forEach</span><span class="p">((</span><span class="nx">item</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">itemId</span> <span class="o">=</span> <span class="s2">`</span><span class="p">${</span><span class="nx">accordionId</span><span class="p">}</span><span class="s2">-item-</span><span class="p">${</span><span class="nx">index</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">expanded</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">expanded</span> <span class="o">&&</span> <span class="nx">params</span><span class="p">.</span><span class="nx">expanded</span><span class="p">.</span><span class="nf">includes</span><span class="p">(</span><span class="nx">index</span><span class="p">.</span><span class="nf">toString</span><span class="p">());</span>
<span class="nx">html</span> <span class="o">+=</span> <span class="s2">`
<div class="accordion-item">
<div class="accordion-header">
<button class="accordion-button</span><span class="p">${</span><span class="nx">expanded</span> <span class="p">?</span> <span class="dl">''</span> <span class="p">:</span> <span class="dl">'</span><span class="s1"> collapsed</span><span class="dl">'</span><span class="p">}</span><span class="s2">"
type="button"
data-toggle="collapse"
data-target="#</span><span class="p">${</span><span class="nx">itemId</span><span class="p">}</span><span class="s2">"
aria-expanded="</span><span class="p">${</span><span class="nx">expanded</span><span class="p">}</span><span class="s2">"
aria-controls="</span><span class="p">${</span><span class="nx">itemId</span><span class="p">}</span><span class="s2">">
</span><span class="p">${</span><span class="nx">item</span><span class="p">.</span><span class="nx">title</span><span class="p">}</span><span class="s2">
</button>
</div>
<div id="</span><span class="p">${</span><span class="nx">itemId</span><span class="p">}</span><span class="s2">" class="accordion-collapse collapse</span><span class="p">${</span><span class="nx">expanded</span> <span class="p">?</span> <span class="dl">'</span><span class="s1"> show</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">" data-parent="#</span><span class="p">${</span><span class="nx">accordionId</span><span class="p">}</span><span class="s2">">
<div class="accordion-body">
</span><span class="p">${</span><span class="nx">item</span><span class="p">.</span><span class="nx">content</span><span class="p">}</span><span class="s2">
</div>
</div>
</div>`</span><span class="p">;</span>
<span class="p">});</span>
<span class="nx">html</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1"></div></span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">html</span><span class="p">;</span>
<span class="p">},</span>
<span class="dl">'</span><span class="s1">collapsible</span><span class="dl">'</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">collapsibleId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">title</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">Click to expand</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">expanded</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">expanded</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">true</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<div class="collapsible">
<button class="collapsible-toggle</span><span class="p">${</span><span class="nx">expanded</span> <span class="p">?</span> <span class="dl">'</span><span class="s1"> expanded</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">"
data-target="#</span><span class="p">${</span><span class="nx">collapsibleId</span><span class="p">}</span><span class="s2">"
aria-expanded="</span><span class="p">${</span><span class="nx">expanded</span><span class="p">}</span><span class="s2">">
<span class="toggle-icon"></span><span class="p">${</span><span class="nx">expanded</span> <span class="p">?</span> <span class="dl">'</span><span class="s1">▼</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">'</span><span class="s1">▶</span><span class="dl">'</span><span class="p">}</span><span class="s2"></span>
</span><span class="p">${</span><span class="nx">title</span><span class="p">}</span><span class="s2">
</button>
<div id="</span><span class="p">${</span><span class="nx">collapsibleId</span><span class="p">}</span><span class="s2">" class="collapsible-content</span><span class="p">${</span><span class="nx">expanded</span> <span class="p">?</span> <span class="dl">'</span><span class="s1"> show</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">">
<div class="collapsible-body">
</span><span class="p">${</span><span class="nx">content</span><span class="p">}</span><span class="s2">
</div>
</div>
</div>`</span><span class="p">;</span>
<span class="p">},</span>
<span class="dl">'</span><span class="s1">modal</span><span class="dl">'</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">modalId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">title</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">triggerText</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">trigger</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">Open Modal</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#</span><span class="p">${</span><span class="nx">modalId</span><span class="p">}</span><span class="s2">">
</span><span class="p">${</span><span class="nx">triggerText</span><span class="p">}</span><span class="s2">
</button>
<div class="modal fade" id="</span><span class="p">${</span><span class="nx">modalId</span><span class="p">}</span><span class="s2">" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
</span><span class="p">${</span><span class="nx">title</span> <span class="p">?</span> <span class="s2">`<div class="modal-header">
<h5 class="modal-title"></span><span class="p">${</span><span class="nx">title</span><span class="p">}</span><span class="s2"></h5>
<button type="button" class="btn-close" data-dismiss="modal"></button>
</div>`</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">
<div class="modal-body">
</span><span class="p">${</span><span class="nx">content</span><span class="p">}</span><span class="s2">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">parseAccordionItems</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">sections</span> <span class="o">=</span> <span class="nx">content</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="sr">/^## /m</span><span class="p">).</span><span class="nf">filter</span><span class="p">(</span><span class="nx">section</span> <span class="o">=></span> <span class="nx">section</span><span class="p">.</span><span class="nf">trim</span><span class="p">());</span>
<span class="k">return</span> <span class="nx">sections</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="nx">section</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">lines</span> <span class="o">=</span> <span class="nx">section</span><span class="p">.</span><span class="nf">trim</span><span class="p">().</span><span class="nf">split</span><span class="p">(</span><span class="dl">'</span><span class="se">\n</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">lines</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
<span class="kd">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="nx">lines</span><span class="p">.</span><span class="nf">slice</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nf">join</span><span class="p">(</span><span class="dl">'</span><span class="se">\n</span><span class="dl">'</span><span class="p">).</span><span class="nf">trim</span><span class="p">();</span>
<span class="k">return</span> <span class="p">{</span> <span class="nx">title</span><span class="p">,</span> <span class="nx">content</span> <span class="p">};</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="na">generateId</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="dl">'</span><span class="s1">interactive-</span><span class="dl">'</span> <span class="o">+</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">random</span><span class="p">().</span><span class="nf">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nf">substr</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">);</span>
<span class="p">},</span>
<span class="na">init</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">system</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Interactive plugin initialized</span><span class="dl">'</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nf">addEventListeners</span><span class="p">();</span>
<span class="p">},</span>
<span class="na">addEventListeners</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nb">document</span><span class="p">.</span><span class="nf">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">click</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Handle collapsible toggles</span>
<span class="k">if </span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nf">matches</span><span class="p">(</span><span class="dl">'</span><span class="s1">.collapsible-toggle</span><span class="dl">'</span><span class="p">))</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">toggleCollapsible</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Handle accordion buttons</span>
<span class="k">if </span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nf">matches</span><span class="p">(</span><span class="dl">'</span><span class="s1">.accordion-button</span><span class="dl">'</span><span class="p">))</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">toggleAccordion</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="na">toggleCollapsible</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">button</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">targetId</span> <span class="o">=</span> <span class="nx">button</span><span class="p">.</span><span class="nf">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-target</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="nx">targetId</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">icon</span> <span class="o">=</span> <span class="nx">button</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">.toggle-icon</span><span class="dl">'</span><span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="nx">content</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">contains</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">))</span> <span class="p">{</span>
<span class="nx">content</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="dl">'</span><span class="s1">expanded</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">aria-expanded</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">false</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">icon</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">▶</span><span class="dl">'</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">content</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="dl">'</span><span class="s1">expanded</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">aria-expanded</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">true</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">icon</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">▼</span><span class="dl">'</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">toggleAccordion</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">button</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">targetId</span> <span class="o">=</span> <span class="nx">button</span><span class="p">.</span><span class="nf">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-target</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="nx">targetId</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">accordion</span> <span class="o">=</span> <span class="nx">button</span><span class="p">.</span><span class="nf">closest</span><span class="p">(</span><span class="dl">'</span><span class="s1">.accordion</span><span class="dl">'</span><span class="p">);</span>
<span class="c1">// Close other items in the same accordion</span>
<span class="nx">accordion</span><span class="p">.</span><span class="nf">querySelectorAll</span><span class="p">(</span><span class="dl">'</span><span class="s1">.accordion-collapse.show</span><span class="dl">'</span><span class="p">).</span><span class="nf">forEach</span><span class="p">(</span><span class="nx">item</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="nx">item</span> <span class="o">!==</span> <span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">item</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">otherButton</span> <span class="o">=</span> <span class="nx">accordion</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="s2">`[data-target="#</span><span class="p">${</span><span class="nx">item</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span><span class="s2">"]`</span><span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="nx">otherButton</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">otherButton</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="dl">'</span><span class="s1">collapsed</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">otherButton</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">aria-expanded</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">false</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="c1">// Toggle current item</span>
<span class="k">if </span><span class="p">(</span><span class="nx">content</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">contains</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">))</span> <span class="p">{</span>
<span class="nx">content</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="dl">'</span><span class="s1">collapsed</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">aria-expanded</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">false</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">content</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="dl">'</span><span class="s1">collapsed</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">aria-expanded</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">true</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="c1">// Initialize plugin system</span>
<span class="kd">const</span> <span class="nx">pluginSystem</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MarkdownDirectivePluginSystem</span><span class="p">();</span>
<span class="c1">// Register plugins</span>
<span class="nx">pluginSystem</span><span class="p">.</span><span class="nf">registerPlugin</span><span class="p">(</span><span class="dl">'</span><span class="s1">charts</span><span class="dl">'</span><span class="p">,</span> <span class="nx">chartPlugin</span><span class="p">);</span>
<span class="nx">pluginSystem</span><span class="p">.</span><span class="nf">registerPlugin</span><span class="p">(</span><span class="dl">'</span><span class="s1">interactive</span><span class="dl">'</span><span class="p">,</span> <span class="nx">interactivePlugin</span><span class="p">);</span>
<span class="c1">// Export for use</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">markdownPluginSystem</span> <span class="o">=</span> <span class="nx">pluginSystem</span><span class="p">;</span>
</code></pre></div></div>
<h2 id="static-site-generator-integration">Static Site Generator Integration</h2>
<h3 id="jekyll-liquid-extension">Jekyll Liquid Extension</h3>
<p>Create Jekyll-compatible directive processing:</p>
<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<!-- _plugins/directive_processor.rb -->
require 'liquid'
module Jekyll
class DirectiveProcessor < Liquid::Block
def initialize(tag_name, params, tokens)
super
@directive_name = tag_name
@params = parse_params(params)
end
def render(context)
content = super
case @directive_name
when 'info'
render_info_block(content, @params)
when 'warning'
render_warning_block(content, @params)
when 'code_example'
render_code_example(content, @params)
when 'definition'
render_definition(content, @params)
else
content
end
end
private
def parse_params(param_string)
params = {}
return params if param_string.nil?
# Parse key="value" pairs
param_string.scan(/(\w+)="([^"]*)"/) do |key, value|
params[key] = value
end
# Parse key=value pairs
param_string.scan(/(\w+)=(\w+)/) do |key, value|
params[key] = value unless params.key?(key)
end
params
end
def render_info_block(content, params)
title = params['title'] || ''
icon = params['icon'] || 'ℹ️'
<<~HTML
<div class="directive-block directive-info">
#{title.empty? ? '' : %(<div class="directive-header">
<span class="directive-icon">#{icon}</span>
<span class="directive-title">#{title}</span>
</div>)}
<div class="directive-content">
#{markdownify(content)}
</div>
</div>
HTML
end
def render_warning_block(content, params)
title = params['title'] || 'Warning'
icon = params['icon'] || '⚠️'
<<~HTML
<div class="directive-block directive-warning">
<div class="directive-header">
<span class="directive-icon">#{icon}</span>
<span class="directive-title">#{title}</span>
</div>
<div class="directive-content">
#{markdownify(content)}
</div>
</div>
HTML
end
def render_code_example(content, params)
language = params['language'] || 'text'
filename = params['filename'] || ''
<<~HTML
<div class="directive-block directive-code-example">
#{filename.empty? ? '' : %(<div class="code-filename">#{filename}</div>)}
<div class="code-container">
<pre class="code-block language-#{language}"><code>#{content.strip}</code></pre>
</div>
</div>
HTML
end
def render_definition(content, params)
term = params['term'] || ''
<<~HTML
<div class="directive-block directive-definition">
<div class="definition-term">#{term}</div>
<div class="definition-content">
#{markdownify(content)}
</div>
</div>
HTML
end
def markdownify(content)
Jekyll::Converters::Markdown.new({}).convert(content)
end
end
end
# Register directive tags
Liquid::Template.register_tag('info', Jekyll::DirectiveProcessor)
Liquid::Template.register_tag('warning', Jekyll::DirectiveProcessor)
Liquid::Template.register_tag('code_example', Jekyll::DirectiveProcessor)
Liquid::Template.register_tag('definition', Jekyll::DirectiveProcessor)
<!-- Usage in Markdown files: -->
<span class="cp">{%</span><span class="w"> </span><span class="nt">info</span><span class="w"> </span><span class="na">title</span><span class="o">=</span><span class="s2">"Important Information"</span><span class="w"> </span><span class="cp">%}</span>
This is important information that readers should notice.
It supports **markdown formatting** and `inline code`.
<span class="cp">{%</span><span class="w"> </span><span class="nt">endinfo</span><span class="w"> </span><span class="cp">%}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">warning</span><span class="w"> </span><span class="na">title</span><span class="o">=</span><span class="s2">"Critical Warning"</span><span class="w"> </span><span class="cp">%}</span>
This is a critical warning with important safety information.
<span class="cp">{%</span><span class="w"> </span><span class="nt">endwarning</span><span class="w"> </span><span class="cp">%}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">code_example</span><span class="w"> </span><span class="na">language</span><span class="o">=</span><span class="s2">"javascript"</span><span class="w"> </span><span class="na">filename</span><span class="o">=</span><span class="s2">"example.js"</span><span class="w"> </span><span class="cp">%}</span>
function exampleFunction() {
console.log("This is an example");
}
<span class="cp">{%</span><span class="w"> </span><span class="nt">endcode_example</span><span class="w"> </span><span class="cp">%}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">definition</span><span class="w"> </span><span class="na">term</span><span class="o">=</span><span class="s2">"API Endpoint"</span><span class="w"> </span><span class="cp">%}</span>
An API endpoint is a specific URL where an API can be accessed by a client application.
<span class="cp">{%</span><span class="w"> </span><span class="nt">enddefinition</span><span class="w"> </span><span class="cp">%}</span>
</code></pre></div></div>
<h3 id="hugo-shortcode-system">Hugo Shortcode System</h3>
<p>Advanced shortcode implementations for Hugo:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// layouts/shortcodes/directive.html</span>
<span class="p">{{</span> <span class="err">$</span><span class="k">type</span> <span class="o">:=</span> <span class="o">.</span><span class="n">Get</span> <span class="s">"type"</span> <span class="o">|</span> <span class="k">default</span> <span class="s">"info"</span> <span class="p">}}</span>
<span class="p">{{</span> <span class="err">$</span><span class="n">title</span> <span class="o">:=</span> <span class="o">.</span><span class="n">Get</span> <span class="s">"title"</span> <span class="p">}}</span>
<span class="p">{{</span> <span class="err">$</span><span class="n">icon</span> <span class="o">:=</span> <span class="o">.</span><span class="n">Get</span> <span class="s">"icon"</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-block directive-{{ $type }}"</span><span class="o">></span>
<span class="p">{{</span> <span class="k">if</span> <span class="err">$</span><span class="n">title</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-header"</span><span class="o">></span>
<span class="p">{{</span> <span class="k">if</span> <span class="err">$</span><span class="n">icon</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">span</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-icon"</span><span class="o">></span><span class="p">{{</span> <span class="err">$</span><span class="n">icon</span> <span class="p">}}</span><span class="o"></</span><span class="n">span</span><span class="o">></span>
<span class="p">{{</span> <span class="k">else</span> <span class="p">}}</span>
<span class="p">{{</span> <span class="k">if</span> <span class="n">eq</span> <span class="err">$</span><span class="k">type</span> <span class="s">"info"</span> <span class="p">}}</span><span class="o"><</span><span class="n">span</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-icon"</span><span class="o">></span><span class="n">ℹ</span><span class="err">️</span><span class="o"></</span><span class="n">span</span><span class="o">></span><span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="p">{{</span> <span class="k">if</span> <span class="n">eq</span> <span class="err">$</span><span class="k">type</span> <span class="s">"warning"</span> <span class="p">}}</span><span class="o"><</span><span class="n">span</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-icon"</span><span class="o">></span><span class="err">⚠️</span><span class="o"></</span><span class="n">span</span><span class="o">></span><span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="p">{{</span> <span class="k">if</span> <span class="n">eq</span> <span class="err">$</span><span class="k">type</span> <span class="s">"example"</span> <span class="p">}}</span><span class="o"><</span><span class="n">span</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-icon"</span><span class="o">></span><span class="err">💡</span><span class="o"></</span><span class="n">span</span><span class="o">></span><span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">span</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-title"</span><span class="o">></span><span class="p">{{</span> <span class="err">$</span><span class="n">title</span> <span class="p">}}</span><span class="o"></</span><span class="n">span</span><span class="o">></span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-content"</span><span class="o">></span>
<span class="p">{{</span> <span class="o">.</span><span class="n">Inner</span> <span class="o">|</span> <span class="n">markdownify</span> <span class="p">}}</span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
</code></pre></div></div>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// layouts/shortcodes/tabs.html</span>
<span class="p">{{</span> <span class="err">$</span><span class="n">tabsId</span> <span class="o">:=</span> <span class="n">printf</span> <span class="s">"tabs-%d"</span> <span class="p">(</span><span class="n">rand</span> <span class="m">1000</span><span class="p">)</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-tabs"</span> <span class="n">data</span><span class="o">-</span><span class="n">tabs</span><span class="o">-</span><span class="n">id</span><span class="o">=</span><span class="s">"{{ $tabsId }}"</span><span class="o">></span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"tab-headers"</span><span class="o">></span>
<span class="p">{{</span> <span class="k">range</span> <span class="err">$</span><span class="n">index</span><span class="p">,</span> <span class="err">$</span><span class="n">tab</span> <span class="o">:=</span> <span class="o">.</span><span class="n">Params</span><span class="o">.</span><span class="n">tabs</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">button</span> <span class="n">class</span><span class="o">=</span><span class="s">"tab-header{{ if eq $index 0 }} active{{ end }}"</span> <span class="n">data</span><span class="o">-</span><span class="n">tab</span><span class="o">=</span><span class="s">"{{ $index }}"</span><span class="o">></span>
<span class="p">{{</span> <span class="err">$</span><span class="n">tab</span><span class="o">.</span><span class="n">title</span> <span class="p">}}</span>
<span class="o"></</span><span class="n">button</span><span class="o">></span>
<span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"tab-contents"</span><span class="o">></span>
<span class="p">{{</span> <span class="k">range</span> <span class="err">$</span><span class="n">index</span><span class="p">,</span> <span class="err">$</span><span class="n">tab</span> <span class="o">:=</span> <span class="o">.</span><span class="n">Params</span><span class="o">.</span><span class="n">tabs</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"tab-content{{ if eq $index 0 }} active{{ end }}"</span> <span class="n">data</span><span class="o">-</span><span class="n">tab</span><span class="o">=</span><span class="s">"{{ $index }}"</span><span class="o">></span>
<span class="p">{{</span> <span class="err">$</span><span class="n">tab</span><span class="o">.</span><span class="n">content</span> <span class="o">|</span> <span class="n">markdownify</span> <span class="p">}}</span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
</code></pre></div></div>
<p>Usage in Hugo Markdown:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{{<span class="nt"><</span> <span class="nt">directive</span> <span class="na">type=</span><span class="s">"info"</span> <span class="na">title=</span><span class="s">"Getting Started"</span> <span class="nt">></span>}}
This is an information block with <span class="gs">**markdown**</span> support.
{{<span class="nt"><</span> <span class="err">/</span><span class="na">directive</span> <span class="nt">></span>}}
{{<span class="nt"><</span> <span class="nt">directive</span> <span class="na">type=</span><span class="s">"warning"</span> <span class="na">title=</span><span class="s">"Important Notice"</span> <span class="nt">></span>}}
This is a warning with critical information.
{{<span class="nt"><</span> <span class="err">/</span><span class="na">directive</span> <span class="nt">></span>}}
{{<span class="nt"><</span> <span class="nt">tabs</span> <span class="nt">></span>}}
{{<span class="nt"><</span> <span class="nt">tab</span> <span class="na">title=</span><span class="s">"JavaScript"</span> <span class="nt">></span>}}
<span class="p">```</span><span class="nl">javascript
</span><span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">Hello World</span><span class="dl">"</span><span class="p">);</span>
</code></pre></div></div>
<p>{{< /tab >}}<br />
{{< tab title=”Python” >}}</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Hello World</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div>
<p>{{< /tab >}}<br />
{{< /tabs >}}</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
## Security and Performance Considerations
### Secure Directive Processing
Implement security measures for custom directives:
```javascript
// secure-directive-processor.js - Security-focused directive processing
class SecureDirectiveProcessor {
constructor(options = {}) {
this.securityConfig = {
allowedTags: ['div', 'span', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'code', 'pre', 'strong', 'em'],
allowedAttributes: ['class', 'id', 'data-*', 'aria-*'],
allowedProtocols: ['http:', 'https:', 'mailto:'],
maxDirectiveDepth: 5,
maxContentLength: 50000,
sanitizeHTML: true,
...options.security
};
this.performanceConfig = {
maxDirectivesPerDocument: 500,
processingTimeout: 5000,
enableCaching: true,
cacheSize: 1000,
...options.performance
};
this.cache = new Map();
this.stats = {
processed: 0,
cached: 0,
errors: 0,
securityViolations: 0
};
}
processContent(content) {
try {
// Pre-processing security checks
if (!this.validateContent(content)) {
throw new Error('Content validation failed');
}
// Check cache first
const cacheKey = this.generateCacheKey(content);
if (this.performanceConfig.enableCaching && this.cache.has(cacheKey)) {
this.stats.cached++;
return this.cache.get(cacheKey);
}
// Process with timeout
const result = this.processWithTimeout(content);
// Cache result
if (this.performanceConfig.enableCaching) {
this.cacheResult(cacheKey, result);
}
this.stats.processed++;
return result;
} catch (error) {
this.stats.errors++;
console.error('Directive processing error:', error);
return this.createErrorResponse(error);
}
}
validateContent(content) {
// Length validation
if (content.length > this.securityConfig.maxContentLength) {
this.stats.securityViolations++;
return false;
}
// Check for suspicious patterns
const suspiciousPatterns = [
/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
/javascript:/gi,
/on\w+\s*=/gi,
/data:(?!image\/[png|jpg|jpeg|gif|svg])/gi
];
for (const pattern of suspiciousPatterns) {
if (pattern.test(content)) {
this.stats.securityViolations++;
return false;
}
}
return true;
}
processWithTimeout(content) {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error('Processing timeout exceeded'));
}, this.performanceConfig.processingTimeout);
try {
const result = this.processDirectives(content);
clearTimeout(timeout);
resolve(result);
} catch (error) {
clearTimeout(timeout);
reject(error);
}
});
}
processDirectives(content) {
// Count directives to prevent abuse
const directiveCount = (content.match(/:::\w+/g) || []).length;
if (directiveCount > this.performanceConfig.maxDirectivesPerDocument) {
throw new Error('Too many directives in document');
}
// Process with depth tracking
return this.processWithDepthTracking(content, 0);
}
processWithDepthTracking(content, depth) {
if (depth > this.securityConfig.maxDirectiveDepth) {
throw new Error('Maximum directive nesting depth exceeded');
}
// Process directives at current level
const directivePattern = /:::(\w+)(?:\s+([^\n]*))?\n([\s\S]*?)\n:::/g;
return content.replace(directivePattern, (match, type, params, innerContent) => {
// Validate directive type
if (!this.isAllowedDirective(type)) {
this.stats.securityViolations++;
return this.createSecurityError(`Directive type '${type}' not allowed`);
}
// Sanitize parameters
const sanitizedParams = this.sanitizeParameters(params);
// Process nested content
const processedContent = this.processWithDepthTracking(innerContent, depth + 1);
// Generate directive HTML
const html = this.generateDirectiveHTML(type, sanitizedParams, processedContent);
// Sanitize output HTML
return this.sanitizeHTML(html);
});
}
isAllowedDirective(type) {
const allowedDirectives = [
'info', 'warning', 'example', 'definition',
'code-example', 'tab-group', 'tab'
];
return allowedDirectives.includes(type);
}
sanitizeParameters(paramString) {
if (!paramString) return {};
const params = {};
const paramPattern = /(\w+)="([^"]*)"/g;
let match;
while ((match = paramPattern.exec(paramString)) !== null) {
const key = match[1];
const value = match[2];
// Validate parameter name
if (!/^\w+$/.test(key)) {
continue;
}
// Sanitize parameter value
params[key] = this.sanitizeParameterValue(value);
}
return params;
}
sanitizeParameterValue(value) {
// Remove potentially dangerous content
return value
.replace(/[<>'"]/g, '')
.replace(/javascript:/gi, '')
.replace(/on\w+/gi, '')
.substring(0, 200); // Limit length
}
sanitizeHTML(html) {
if (!this.securityConfig.sanitizeHTML) {
return html;
}
// Basic HTML sanitization
const div = document.createElement('div');
div.innerHTML = html;
// Remove disallowed tags
this.removeDisallowedElements(div);
// Sanitize attributes
this.sanitizeAttributes(div);
return div.innerHTML;
}
removeDisallowedElements(container) {
const elements = container.querySelectorAll('*');
elements.forEach(element => {
if (!this.securityConfig.allowedTags.includes(element.tagName.toLowerCase())) {
element.remove();
}
});
}
sanitizeAttributes(container) {
const elements = container.querySelectorAll('*');
elements.forEach(element => {
const attributesToRemove = [];
for (const attr of element.attributes) {
if (!this.isAllowedAttribute(attr.name)) {
attributesToRemove.push(attr.name);
} else if (attr.name === 'href' || attr.name === 'src') {
if (!this.isAllowedURL(attr.value)) {
attributesToRemove.push(attr.name);
}
}
}
attributesToRemove.forEach(attrName => {
element.removeAttribute(attrName);
});
});
}
isAllowedAttribute(attrName) {
return this.securityConfig.allowedAttributes.some(allowed => {
if (allowed.endsWith('*')) {
return attrName.startsWith(allowed.slice(0, -1));
}
return attrName === allowed;
});
}
isAllowedURL(url) {
try {
const parsed = new URL(url, window.location.href);
return this.securityConfig.allowedProtocols.includes(parsed.protocol);
} catch {
return false;
}
}
generateDirectiveHTML(type, params, content) {
// Use safe HTML generation methods
switch (type) {
case 'info':
return this.generateInfoDirective(params, content);
case 'warning':
return this.generateWarningDirective(params, content);
default:
return content;
}
}
generateInfoDirective(params, content) {
const title = params.title || '';
return `
<div class="directive-block directive-info">
${title ? `<div class="directive-header">
<span class="directive-title">${this.escapeHTML(title)}</span>
</div>` : ''}
<div class="directive-content">${content}</div>
</div>`;
}
generateWarningDirective(params, content) {
const title = params.title || 'Warning';
return `
<div class="directive-block directive-warning">
<div class="directive-header">
<span class="directive-title">${this.escapeHTML(title)}</span>
</div>
<div class="directive-content">${content}</div>
</div>`;
}
escapeHTML(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
generateCacheKey(content) {
// Simple hash function for cache keys
let hash = 0;
for (let i = 0; i < content.length; i++) {
const char = content.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash.toString();
}
cacheResult(key, result) {
if (this.cache.size >= this.performanceConfig.cacheSize) {
// Remove oldest entry
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, result);
}
createErrorResponse(error) {
return `<div class="directive-error">Error processing directives: ${this.escapeHTML(error.message)}</div>`;
}
createSecurityError(message) {
return `<div class="directive-security-error">Security violation: ${this.escapeHTML(message)}</div>`;
}
getStats() {
return {
...this.stats,
cacheSize: this.cache.size,
cacheHitRate: this.stats.cached / (this.stats.processed + this.stats.cached)
};
}
clearCache() {
this.cache.clear();
}
}
// Initialize secure processor
const secureProcessor = new SecureDirectiveProcessor({
security: {
allowedTags: ['div', 'span', 'p', 'code', 'pre', 'strong', 'em', 'h1', 'h2', 'h3', 'h4'],
allowedAttributes: ['class', 'id', 'data-*', 'aria-*'],
maxDirectiveDepth: 3,
maxContentLength: 100000
},
performance: {
maxDirectivesPerDocument: 200,
processingTimeout: 3000,
enableCaching: true
}
});
</code></pre></div></div>
<h2 id="integration-with-modern-documentation-systems">Integration with Modern Documentation Systems</h2>
<p>Custom directive systems integrate seamlessly with comprehensive content management platforms. When combined with <a href="https://blog.markdowntools.com/posts/markdown-automation-workflows-complete-guide">automation workflows and content processing</a>, custom directives enable sophisticated build processes that can validate content, generate interactive components, and maintain consistency across large documentation projects.</p>
<p>For advanced content architectures, directive systems work effectively with <a href="https://blog.markdowntools.com/posts/markdown-progressive-web-app-documentation-complete-guide">Progressive Web App documentation platforms</a> to provide offline functionality, cached interactive components, and enhanced user experiences for technical documentation systems.</p>
<p>When building comprehensive documentation ecosystems, custom directives complement <a href="https://blog.markdowntools.com/posts/markdown-table-performance-optimization-for-large-datasets">advanced table management and data presentation systems</a> by enabling contextual content blocks, interactive data visualizations, and sophisticated information organization patterns.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Custom Markdown directives and block extensions transform static content into dynamic, interactive documentation platforms that maintain Markdown’s simplicity while providing powerful extensibility. By implementing systematic directive processors, creating reusable content components, and establishing secure extension architectures, technical teams can build sophisticated content management systems that scale with project requirements while maintaining consistency and performance.</p>
<p>The key to successful directive implementation lies in balancing functionality with security, establishing clear syntax conventions, and creating maintainable processing systems that can evolve with changing requirements. Whether you’re building technical documentation, educational content, or interactive guides, the directive techniques covered in this guide provide the foundation for creating rich, engaging content experiences.</p>
<p>Remember to prioritize security in directive processing, implement comprehensive error handling, and establish clear guidelines for directive usage within your team. With proper implementation of custom Markdown directive systems, your documentation can achieve new levels of interactivity and user engagement while preserving the clean, readable format that makes Markdown an effective content creation tool.</p>
</div><a class="u-url" href="/posts/markdown-custom-directives-block-extensions-complete-guide" hidden></a>
</article>
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
<header class="post-header">
<h1 class="post-title p-name" itemprop="name headline">Markdown Custom Directives and Block Extensions: Complete Guide to Advanced Content Blocks and Interactive Components</h1>
<p class="post-meta"><time class="dt-published" datetime="2025-12-30T00:00:00+00:00" itemprop="datePublished">
Dec 30, 2025
</time>•
<span itemprop="author" itemscope itemtype="http://schema.org/Person">
<span class="p-author h-card" itemprop="name">Matthew Rathbone</span></span></p>
</header>
<div class="post-content e-content" itemprop="articleBody">
<p>Custom Markdown directives and block extensions enable sophisticated content creation through extensible syntax systems, interactive components, and advanced formatting capabilities that extend beyond standard Markdown limitations. By implementing custom directive processors, developing reusable content blocks, and creating sophisticated extension systems, technical writers and developers can build powerful documentation platforms that combine Markdown’s simplicity with the flexibility of custom content components and interactive elements.</p>
<h2 id="why-use-custom-directives-and-block-extensions">Why Use Custom Directives and Block Extensions?</h2>
<p>Advanced Markdown extensibility provides essential capabilities for modern content systems:</p>
<ul>
<li><strong>Enhanced Content Components</strong>: Create reusable, interactive content blocks beyond basic Markdown</li>
<li><strong>Custom Syntax Systems</strong>: Develop domain-specific markup languages for specialized content types</li>
<li><strong>Interactive Documentation</strong>: Build dynamic content with embedded functionality and user interactions</li>
<li><strong>Content Management Integration</strong>: Connect Markdown with external data sources and content management systems</li>
<li><strong>Platform Consistency</strong>: Ensure consistent styling and behavior across different content platforms</li>
</ul>
<h2 id="foundation-directive-systems">Foundation Directive Systems</h2>
<h3 id="basic-directive-syntax-patterns">Basic Directive Syntax Patterns</h3>
<p>Common approaches to custom directive implementation:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># Standard Directive Patterns</span>
<span class="gu">## Block Directive Syntax</span>
:::info
This is an information block with custom styling and behavior.
:::
:::warning title="Important Notice"
This is a warning block with a custom title parameter.
:::
:::code-example language="javascript" filename="example.js"
<span class="p">```</span><span class="nl">javascript
</span><span class="kd">function</span> <span class="nf">customDirective</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">Custom directive content</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">```</span>
::::
<span class="gu">## Inline Directive Syntax</span>
This paragraph contains an inline {%note%}important note{%/note%} directive.
Use {%badge color="primary"%}Custom Badge{%/badge%} for highlighting.
Insert {%icon name="warning"%} for contextual icons.
<span class="gu">## Parameterized Directives</span>
:::tab-group
:::tab title="JavaScript"
<span class="p">```</span><span class="nl">javascript
</span><span class="c1">// JavaScript implementation</span>
<span class="p">```</span>
:::
:::tab title="Python"
<span class="p">```</span><span class="nl">python
</span><span class="c1"># Python implementation</span>
<span class="p">```</span>
:::
:::
<span class="gu">## Content-Rich Directives</span>
:::definition term="API Gateway"
An API Gateway is a server that acts as an API front-end, receiving API requests, enforcing throttling and security policies, passing requests to the back-end service, and then passing the response back to the requester.
<span class="gs">**Key Features:**</span>
<span class="p">-</span> Request routing and composition
<span class="p">-</span> Authentication and authorization
<span class="p">-</span> Rate limiting and throttling
<span class="p">-</span> Request and response transformation
:::
:::example
<span class="gs">**Problem**</span>: How to implement user authentication?
<span class="gs">**Solution**</span>: Use JSON Web Tokens (JWT) for stateless authentication.
<span class="p">```</span><span class="nl">javascript
</span><span class="kd">const</span> <span class="nx">jwt</span> <span class="o">=</span> <span class="nf">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">jsonwebtoken</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">function</span> <span class="nf">generateToken</span><span class="p">(</span><span class="nx">user</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">jwt</span><span class="p">.</span><span class="nf">sign</span><span class="p">(</span>
<span class="p">{</span> <span class="na">id</span><span class="p">:</span> <span class="nx">user</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span> <span class="na">email</span><span class="p">:</span> <span class="nx">user</span><span class="p">.</span><span class="nx">email</span> <span class="p">},</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">JWT_SECRET</span><span class="p">,</span>
<span class="p">{</span> <span class="na">expiresIn</span><span class="p">:</span> <span class="dl">'</span><span class="s1">1h</span><span class="dl">'</span> <span class="p">}</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="p">```</span>
<span class="gs">**Explanation**</span>: This creates a secure token that can be verified without server-side session storage.
:::
</code></pre></div></div>
<h3 id="advanced-directive-processors">Advanced Directive Processors</h3>
<p>Creating sophisticated directive processing systems:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// markdown-directive-processor.js - Comprehensive directive processing system</span>
<span class="kd">class</span> <span class="nc">MarkdownDirectiveProcessor</span> <span class="p">{</span>
<span class="nf">constructor</span><span class="p">(</span><span class="nx">options</span> <span class="o">=</span> <span class="p">{})</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">allowCustomHTML</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
<span class="na">validateDirectives</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">customDirectives</span><span class="p">:</span> <span class="k">new</span> <span class="nc">Map</span><span class="p">(),</span>
<span class="na">templateEngine</span><span class="p">:</span> <span class="dl">'</span><span class="s1">default</span><span class="dl">'</span><span class="p">,</span>
<span class="na">securityLevel</span><span class="p">:</span> <span class="dl">'</span><span class="s1">strict</span><span class="dl">'</span><span class="p">,</span>
<span class="p">...</span><span class="nx">options</span>
<span class="p">};</span>
<span class="k">this</span><span class="p">.</span><span class="nx">directiveRegistry</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Map</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">templateCache</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Map</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">directivesProcessed</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="na">errors</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="na">warnings</span><span class="p">:</span> <span class="mi">0</span>
<span class="p">};</span>
<span class="k">this</span><span class="p">.</span><span class="nf">initializeBuiltinDirectives</span><span class="p">();</span>
<span class="p">}</span>
<span class="nf">initializeBuiltinDirectives</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// Register built-in directive types</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">info</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createInfoBlock</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">warning</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createWarningBlock</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">code-example</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createCodeExample</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">definition</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createDefinition</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">example</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createExample</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">tab-group</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createTabGroup</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">tab</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createTab</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">note</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createInlineNote</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">badge</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createBadge</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="dl">'</span><span class="s1">icon</span><span class="dl">'</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">createIcon</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
<span class="p">}</span>
<span class="nf">registerDirective</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">processor</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nx">processor</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">function</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="s2">`Directive processor for '</span><span class="p">${</span><span class="nx">name</span><span class="p">}</span><span class="s2">' must be a function`</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">directiveRegistry</span><span class="p">.</span><span class="nf">set</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="p">{</span>
<span class="nx">processor</span><span class="p">,</span>
<span class="na">registeredAt</span><span class="p">:</span> <span class="k">new</span> <span class="nc">Date</span><span class="p">(),</span>
<span class="na">usageCount</span><span class="p">:</span> <span class="mi">0</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="nf">processMarkdown</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="c1">// Process block directives first</span>
<span class="nx">content</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">processBlockDirectives</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="c1">// Then process inline directives</span>
<span class="nx">content</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">processInlineDirectives</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="c1">// Post-process for nested directives</span>
<span class="nx">content</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">processNestedDirectives</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">content</span><span class="p">;</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">errors</span><span class="o">++</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Directive processing error:</span><span class="dl">'</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">content</span><span class="p">;</span> <span class="c1">// Return original content on error</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nf">processBlockDirectives</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Pattern for block directives: :::directive-name params\ncontent\n:::</span>
<span class="kd">const</span> <span class="nx">blockDirectivePattern</span> <span class="o">=</span> <span class="sr">/:::</span><span class="se">(\w</span><span class="sr">+</span><span class="se">)(?:\s</span><span class="sr">+</span><span class="se">([^\n]</span><span class="sr">*</span><span class="se">))?\n([\s\S]</span><span class="sr">*</span><span class="se">?)\n</span><span class="sr">:::/g</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">content</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="nx">blockDirectivePattern</span><span class="p">,</span> <span class="p">(</span><span class="nx">match</span><span class="p">,</span> <span class="nx">directiveName</span><span class="p">,</span> <span class="nx">params</span><span class="p">,</span> <span class="nx">directiveContent</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">directivesProcessed</span><span class="o">++</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">directive</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">directiveRegistry</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="nx">directiveName</span><span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">directive</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">warnings</span><span class="o">++</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">warn</span><span class="p">(</span><span class="s2">`Unknown directive: </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nf">createErrorBlock</span><span class="p">(</span><span class="s2">`Unknown directive: </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">directive</span><span class="p">.</span><span class="nx">usageCount</span><span class="o">++</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">parsedParams</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseDirectiveParams</span><span class="p">(</span><span class="nx">params</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">context</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">name</span><span class="p">:</span> <span class="nx">directiveName</span><span class="p">,</span>
<span class="na">params</span><span class="p">:</span> <span class="nx">parsedParams</span><span class="p">,</span>
<span class="na">content</span><span class="p">:</span> <span class="nx">directiveContent</span><span class="p">.</span><span class="nf">trim</span><span class="p">(),</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">block</span><span class="dl">'</span>
<span class="p">};</span>
<span class="k">return</span> <span class="nx">directive</span><span class="p">.</span><span class="nf">processor</span><span class="p">(</span><span class="nx">context</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">errors</span><span class="o">++</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="s2">`Error processing directive </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">:`</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nf">createErrorBlock</span><span class="p">(</span><span class="s2">`Error in directive: </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="nf">processInlineDirectives</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Pattern for inline directives: {%directive-name params%}content{%/directive-name%}</span>
<span class="kd">const</span> <span class="nx">inlineDirectivePattern</span> <span class="o">=</span> <span class="sr">/</span><span class="se">\{</span><span class="sr">%</span><span class="se">(\w</span><span class="sr">+</span><span class="se">)(?:\s</span><span class="sr">+</span><span class="se">([^</span><span class="sr">%</span><span class="se">]</span><span class="sr">*</span><span class="se">))?\%\}(</span><span class="sr">.*</span><span class="se">?)\{</span><span class="sr">%</span><span class="se">\/\1\%\}</span><span class="sr">/g</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">content</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="nx">inlineDirectivePattern</span><span class="p">,</span> <span class="p">(</span><span class="nx">match</span><span class="p">,</span> <span class="nx">directiveName</span><span class="p">,</span> <span class="nx">params</span><span class="p">,</span> <span class="nx">directiveContent</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">directivesProcessed</span><span class="o">++</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">directive</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">directiveRegistry</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="nx">directiveName</span><span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">directive</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">warnings</span><span class="o">++</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">warn</span><span class="p">(</span><span class="s2">`Unknown inline directive: </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="k">return</span> <span class="s2">`<span class="directive-error">Unknown directive: </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2"></span>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">directive</span><span class="p">.</span><span class="nx">usageCount</span><span class="o">++</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">parsedParams</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseDirectiveParams</span><span class="p">(</span><span class="nx">params</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">context</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">name</span><span class="p">:</span> <span class="nx">directiveName</span><span class="p">,</span>
<span class="na">params</span><span class="p">:</span> <span class="nx">parsedParams</span><span class="p">,</span>
<span class="na">content</span><span class="p">:</span> <span class="nx">directiveContent</span><span class="p">.</span><span class="nf">trim</span><span class="p">(),</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">inline</span><span class="dl">'</span>
<span class="p">};</span>
<span class="k">return</span> <span class="nx">directive</span><span class="p">.</span><span class="nf">processor</span><span class="p">(</span><span class="nx">context</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">.</span><span class="nx">errors</span><span class="o">++</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="s2">`Error processing inline directive </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">:`</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
<span class="k">return</span> <span class="s2">`<span class="directive-error">Error in directive: </span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2"></span>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="nf">processNestedDirectives</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Handle special cases like tab-group containers</span>
<span class="k">return</span> <span class="nx">content</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/:::tab-group</span><span class="se">\n([\s\S]</span><span class="sr">*</span><span class="se">?)\n</span><span class="sr">:::/g</span><span class="p">,</span> <span class="p">(</span><span class="nx">match</span><span class="p">,</span> <span class="nx">tabsContent</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">tabs</span> <span class="o">=</span> <span class="p">[];</span>
<span class="kd">const</span> <span class="nx">tabPattern</span> <span class="o">=</span> <span class="sr">/:::tab</span><span class="se">\s</span><span class="sr">+title="</span><span class="se">([^</span><span class="sr">"</span><span class="se">]</span><span class="sr">+</span><span class="se">)</span><span class="sr">"</span><span class="se">(?:\s</span><span class="sr">+</span><span class="se">([^\n]</span><span class="sr">*</span><span class="se">))?\n([\s\S]</span><span class="sr">*</span><span class="se">?)(?=</span><span class="sr">:::tab|$</span><span class="se">)</span><span class="sr">/g</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">tabMatch</span><span class="p">;</span>
<span class="k">while </span><span class="p">((</span><span class="nx">tabMatch</span> <span class="o">=</span> <span class="nx">tabPattern</span><span class="p">.</span><span class="nf">exec</span><span class="p">(</span><span class="nx">tabsContent</span><span class="p">))</span> <span class="o">!==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">tabs</span><span class="p">.</span><span class="nf">push</span><span class="p">({</span>
<span class="na">title</span><span class="p">:</span> <span class="nx">tabMatch</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
<span class="na">params</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseDirectiveParams</span><span class="p">(</span><span class="nx">tabMatch</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">||</span> <span class="dl">''</span><span class="p">),</span>
<span class="na">content</span><span class="p">:</span> <span class="nx">tabMatch</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="nf">trim</span><span class="p">()</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nf">createTabGroup</span><span class="p">({</span> <span class="na">content</span><span class="p">:</span> <span class="dl">''</span><span class="p">,</span> <span class="na">params</span><span class="p">:</span> <span class="p">{},</span> <span class="nx">tabs</span> <span class="p">});</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="nf">parseDirectiveParams</span><span class="p">(</span><span class="nx">paramString</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">paramString</span><span class="p">)</span> <span class="k">return</span> <span class="p">{};</span>
<span class="kd">const</span> <span class="nx">params</span> <span class="o">=</span> <span class="p">{};</span>
<span class="c1">// Handle quoted parameters: key="value"</span>
<span class="kd">const</span> <span class="nx">quotedParamPattern</span> <span class="o">=</span> <span class="sr">/</span><span class="se">(\w</span><span class="sr">+</span><span class="se">)</span><span class="sr">="</span><span class="se">([^</span><span class="sr">"</span><span class="se">]</span><span class="sr">*</span><span class="se">)</span><span class="sr">"/g</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">match</span><span class="p">;</span>
<span class="k">while </span><span class="p">((</span><span class="nx">match</span> <span class="o">=</span> <span class="nx">quotedParamPattern</span><span class="p">.</span><span class="nf">exec</span><span class="p">(</span><span class="nx">paramString</span><span class="p">))</span> <span class="o">!==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">params</span><span class="p">[</span><span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">=</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="p">}</span>
<span class="c1">// Handle unquoted parameters: key=value</span>
<span class="kd">const</span> <span class="nx">unquotedParamPattern</span> <span class="o">=</span> <span class="sr">/</span><span class="se">(\w</span><span class="sr">+</span><span class="se">)</span><span class="sr">=</span><span class="se">(\w</span><span class="sr">+</span><span class="se">)</span><span class="sr">/g</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">cleanedString</span> <span class="o">=</span> <span class="nx">paramString</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="nx">quotedParamPattern</span><span class="p">,</span> <span class="dl">''</span><span class="p">);</span>
<span class="k">while </span><span class="p">((</span><span class="nx">match</span> <span class="o">=</span> <span class="nx">unquotedParamPattern</span><span class="p">.</span><span class="nf">exec</span><span class="p">(</span><span class="nx">cleanedString</span><span class="p">))</span> <span class="o">!==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">params</span><span class="p">[</span><span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">=</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="p">}</span>
<span class="c1">// Handle boolean flags: just the parameter name</span>
<span class="kd">const</span> <span class="nx">remainingString</span> <span class="o">=</span> <span class="nx">cleanedString</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="nx">unquotedParamPattern</span><span class="p">,</span> <span class="dl">''</span><span class="p">).</span><span class="nf">trim</span><span class="p">();</span>
<span class="k">if </span><span class="p">(</span><span class="nx">remainingString</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">remainingString</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="sr">/</span><span class="se">\s</span><span class="sr">+/</span><span class="p">).</span><span class="nf">forEach</span><span class="p">(</span><span class="nx">flag</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="nx">flag</span> <span class="o">&&</span> <span class="o">!</span><span class="nx">params</span><span class="p">[</span><span class="nx">flag</span><span class="p">])</span> <span class="p">{</span>
<span class="nx">params</span><span class="p">[</span><span class="nx">flag</span><span class="p">]</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">params</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Built-in directive implementations</span>
<span class="nf">createInfoBlock</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">title</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">icon</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">icon</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">ℹ️</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<div class="directive-block directive-info">
</span><span class="p">${</span><span class="nx">title</span> <span class="p">?</span> <span class="s2">`<div class="directive-header">
<span class="directive-icon"></span><span class="p">${</span><span class="nx">icon</span><span class="p">}</span><span class="s2"></span>
<span class="directive-title"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">title</span><span class="p">)}</span><span class="s2"></span>
</div>`</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">
<div class="directive-content">
</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">processInnerContent</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2">
</div>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createWarningBlock</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">title</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">Warning</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">icon</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">icon</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">⚠️</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<div class="directive-block directive-warning">
<div class="directive-header">
<span class="directive-icon"></span><span class="p">${</span><span class="nx">icon</span><span class="p">}</span><span class="s2"></span>
<span class="directive-title"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">title</span><span class="p">)}</span><span class="s2"></span>
</div>
<div class="directive-content">
</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">processInnerContent</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2">
</div>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createCodeExample</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">language</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">language</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">text</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">filename</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">filename</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">highlight</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">highlight</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<div class="directive-block directive-code-example">
</span><span class="p">${</span><span class="nx">filename</span> <span class="p">?</span> <span class="s2">`<div class="code-filename"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">filename</span><span class="p">)}</span><span class="s2"></div>`</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">
<div class="code-container">
<pre class="code-block language-</span><span class="p">${</span><span class="nx">language</span><span class="p">}</span><span class="s2">"</span><span class="p">${</span><span class="nx">highlight</span> <span class="p">?</span> <span class="s2">` data-highlight="</span><span class="p">${</span><span class="nx">highlight</span><span class="p">}</span><span class="s2">"`</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">><code></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2"></code></pre>
</div>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createDefinition</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">term</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">term</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<div class="directive-block directive-definition">
<div class="definition-term"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">term</span><span class="p">)}</span><span class="s2"></div>
<div class="definition-content">
</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">processInnerContent</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2">
</div>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createExample</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">title</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">Example</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<div class="directive-block directive-example">
<div class="directive-header">
<span class="directive-icon">💡</span>
<span class="directive-title"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">title</span><span class="p">)}</span><span class="s2"></span>
</div>
<div class="directive-content">
</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">processInnerContent</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2">
</div>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createTabGroup</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">tabs</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">tabs</span> <span class="o">||</span> <span class="nx">tabs</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="dl">''</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">tabsId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="kd">let</span> <span class="nx">tabsHtml</span> <span class="o">=</span> <span class="s2">`<div class="directive-tabs" data-tabs-id="</span><span class="p">${</span><span class="nx">tabsId</span><span class="p">}</span><span class="s2">">`</span><span class="p">;</span>
<span class="c1">// Create tab headers</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1"><div class="tab-headers"></span><span class="dl">'</span><span class="p">;</span>
<span class="nx">tabs</span><span class="p">.</span><span class="nf">forEach</span><span class="p">((</span><span class="nx">tab</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">activeClass</span> <span class="o">=</span> <span class="nx">index</span> <span class="o">===</span> <span class="mi">0</span> <span class="p">?</span> <span class="dl">'</span><span class="s1"> active</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">''</span><span class="p">;</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="s2">`<button class="tab-header</span><span class="p">${</span><span class="nx">activeClass</span><span class="p">}</span><span class="s2">" data-tab="</span><span class="p">${</span><span class="nx">index</span><span class="p">}</span><span class="s2">"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">tab</span><span class="p">.</span><span class="nx">title</span><span class="p">)}</span><span class="s2"></button>`</span><span class="p">;</span>
<span class="p">});</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1"></div></span><span class="dl">'</span><span class="p">;</span>
<span class="c1">// Create tab content</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1"><div class="tab-contents"></span><span class="dl">'</span><span class="p">;</span>
<span class="nx">tabs</span><span class="p">.</span><span class="nf">forEach</span><span class="p">((</span><span class="nx">tab</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">activeClass</span> <span class="o">=</span> <span class="nx">index</span> <span class="o">===</span> <span class="mi">0</span> <span class="p">?</span> <span class="dl">'</span><span class="s1"> active</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">''</span><span class="p">;</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="s2">`<div class="tab-content</span><span class="p">${</span><span class="nx">activeClass</span><span class="p">}</span><span class="s2">" data-tab="</span><span class="p">${</span><span class="nx">index</span><span class="p">}</span><span class="s2">">
</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">processInnerContent</span><span class="p">(</span><span class="nx">tab</span><span class="p">.</span><span class="nx">content</span><span class="p">)}</span><span class="s2">
</div>`</span><span class="p">;</span>
<span class="p">});</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1"></div></span><span class="dl">'</span><span class="p">;</span>
<span class="nx">tabsHtml</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1"></div></span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">tabsHtml</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createTab</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// This is handled by createTabGroup, but we need the method for registration</span>
<span class="k">return</span> <span class="dl">''</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createInlineNote</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">type</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">type</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">info</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`<span class="directive-inline directive-note directive-note-</span><span class="p">${</span><span class="nx">type</span><span class="p">}</span><span class="s2">"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2"></span>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createBadge</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">color</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">color</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">primary</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">size</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">size</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">normal</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`<span class="directive-badge badge-</span><span class="p">${</span><span class="nx">color</span><span class="p">}</span><span class="s2"> badge-</span><span class="p">${</span><span class="nx">size</span><span class="p">}</span><span class="s2">"></span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">content</span><span class="p">)}</span><span class="s2"></span>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createIcon</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">name</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">name</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">size</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">size</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">name</span><span class="p">)</span> <span class="k">return</span> <span class="dl">''</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`<span class="directive-icon icon-</span><span class="p">${</span><span class="nx">name</span><span class="p">}${</span><span class="nx">size</span> <span class="p">?</span> <span class="s2">` icon-</span><span class="p">${</span><span class="nx">size</span><span class="p">}</span><span class="s2">`</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">" aria-hidden="true"></span>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">createErrorBlock</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="s2">`
<div class="directive-error-block">
<strong>Directive Error:</strong> </span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">message</span><span class="p">)}</span><span class="s2">
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">processInnerContent</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Process Markdown within directive content</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="k">this</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">markdownProcessor</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">function</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nf">markdownProcessor</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Basic markdown processing for common cases</span>
<span class="k">return</span> <span class="nx">content</span>
<span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/</span><span class="se">\*\*(</span><span class="sr">.*</span><span class="se">?)\*\*</span><span class="sr">/g</span><span class="p">,</span> <span class="dl">'</span><span class="s1"><strong>$1</strong></span><span class="dl">'</span><span class="p">)</span>
<span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/</span><span class="se">\*(</span><span class="sr">.*</span><span class="se">?)\*</span><span class="sr">/g</span><span class="p">,</span> <span class="dl">'</span><span class="s1"><em>$1</em></span><span class="dl">'</span><span class="p">)</span>
<span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/`</span><span class="se">(</span><span class="sr">.*</span><span class="se">?)</span><span class="sr">`/g</span><span class="p">,</span> <span class="dl">'</span><span class="s1"><code>$1</code></span><span class="dl">'</span><span class="p">)</span>
<span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/</span><span class="se">\n\n</span><span class="sr">/g</span><span class="p">,</span> <span class="dl">'</span><span class="s1"></p><p></span><span class="dl">'</span><span class="p">)</span>
<span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/^</span><span class="se">(?!</span><span class="sr"><p></span><span class="se">)</span><span class="sr">/</span><span class="p">,</span> <span class="dl">'</span><span class="s1"><p></span><span class="dl">'</span><span class="p">)</span>
<span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/</span><span class="se">(?<</span><span class="sr">!<</span><span class="se">\/</span><span class="sr">p></span><span class="se">)</span><span class="sr">$/</span><span class="p">,</span> <span class="dl">'</span><span class="s1"></p></span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">div</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="dl">'</span><span class="s1">div</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">div</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="nx">text</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">div</span><span class="p">.</span><span class="nx">innerHTML</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">generateId</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">random</span><span class="p">().</span><span class="nf">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nf">substr</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">getStats</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span>
<span class="p">...</span><span class="k">this</span><span class="p">.</span><span class="nx">processingStats</span><span class="p">,</span>
<span class="na">registeredDirectives</span><span class="p">:</span> <span class="nb">Array</span><span class="p">.</span><span class="k">from</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">directiveRegistry</span><span class="p">.</span><span class="nf">keys</span><span class="p">()),</span>
<span class="na">directiveUsage</span><span class="p">:</span> <span class="nb">Array</span><span class="p">.</span><span class="k">from</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">directiveRegistry</span><span class="p">.</span><span class="nf">entries</span><span class="p">()).</span><span class="nf">map</span><span class="p">(([</span><span class="nx">name</span><span class="p">,</span> <span class="nx">data</span><span class="p">])</span> <span class="o">=></span> <span class="p">({</span>
<span class="nx">name</span><span class="p">,</span>
<span class="na">usageCount</span><span class="p">:</span> <span class="nx">data</span><span class="p">.</span><span class="nx">usageCount</span>
<span class="p">}))</span>
<span class="p">};</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Initialize directive processor</span>
<span class="kd">const</span> <span class="nx">directiveProcessor</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MarkdownDirectiveProcessor</span><span class="p">();</span>
<span class="c1">// CSS for directive styling</span>
<span class="kd">const</span> <span class="nx">directiveStyles</span> <span class="o">=</span> <span class="s2">`
/* Directive Block Styles */
.directive-block {
margin: 1.5rem 0;
border-radius: 0.375rem;
overflow: hidden;
}
.directive-info {
background: #e3f2fd;
border-left: 4px solid #2196f3;
}
.directive-warning {
background: #fff3cd;
border-left: 4px solid #ff9800;
}
.directive-example {
background: #f0f9ff;
border-left: 4px solid #0ea5e9;
}
.directive-definition {
background: #f8f9fa;
border: 1px solid #dee2e6;
}
.directive-header {
display: flex;
align-items: center;
padding: 0.75rem 1rem;
background: rgba(0,0,0,0.05);
font-weight: 600;
}
.directive-icon {
margin-right: 0.5rem;
font-size: 1.1em;
}
.directive-content {
padding: 1rem;
}
.directive-content p:last-child {
margin-bottom: 0;
}
/* Code Example Styles */
.directive-code-example {
background: #f8f9fa;
border: 1px solid #dee2e6;
}
.code-filename {
background: #495057;
color: white;
padding: 0.5rem 1rem;
font-family: monospace;
font-size: 0.9rem;
}
.code-container {
overflow-x: auto;
}
.code-block {
margin: 0;
padding: 1rem;
background: #f8f9fa;
border: none;
font-family: 'Courier New', monospace;
line-height: 1.5;
}
/* Tab Styles */
.directive-tabs {
border: 1px solid #dee2e6;
border-radius: 0.375rem;
overflow: hidden;
}
.tab-headers {
display: flex;
background: #f8f9fa;
border-bottom: 1px solid #dee2e6;
}
.tab-header {
background: none;
border: none;
padding: 0.75rem 1rem;
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.2s ease;
}
.tab-header:hover {
background: #e9ecef;
}
.tab-header.active {
background: white;
border-bottom-color: #007cba;
color: #007cba;
font-weight: 600;
}
.tab-contents {
position: relative;
}
.tab-content {
display: none;
padding: 1rem;
}
.tab-content.active {
display: block;
}
/* Inline Directive Styles */
.directive-inline {
display: inline;
}
.directive-note {
padding: 0.2rem 0.4rem;
border-radius: 0.25rem;
font-size: 0.9rem;
}
.directive-note-info {
background: #cfe2ff;
color: #084298;
}
.directive-note-warning {
background: #fff3cd;
color: #664d03;
}
.directive-badge {
display: inline-block;
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
font-weight: 600;
line-height: 1;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: 0.375rem;
}
.badge-primary {
color: white;
background-color: #007cba;
}
.badge-success {
color: white;
background-color: #28a745;
}
.badge-warning {
color: #212529;
background-color: #ffc107;
}
.badge-danger {
color: white;
background-color: #dc3545;
}
.badge-small {
padding: 0.125rem 0.375rem;
font-size: 0.75rem;
}
.badge-large {
padding: 0.375rem 0.75rem;
font-size: 1rem;
}
/* Definition Styles */
.definition-term {
font-weight: 700;
font-size: 1.1em;
color: #495057;
margin-bottom: 0.5rem;
}
.definition-content {
color: #6c757d;
}
/* Error Styles */
.directive-error-block {
background: #f8d7da;
color: #721c24;
padding: 1rem;
border: 1px solid #f5c6cb;
border-radius: 0.375rem;
margin: 1rem 0;
}
.directive-error {
color: #dc3545;
font-style: italic;
}
/* Responsive Design */
@media (max-width: 768px) {
.directive-block {
margin: 1rem 0;
}
.directive-header,
.directive-content {
padding: 0.75rem;
}
.tab-headers {
flex-wrap: wrap;
}
.tab-header {
min-width: 0;
flex: 1;
}
}
`</span><span class="p">;</span>
<span class="c1">// JavaScript for interactive functionality</span>
<span class="kd">const</span> <span class="nx">directiveInteractions</span> <span class="o">=</span> <span class="s2">`
// Tab functionality
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.directive-tabs').forEach(tabGroup => {
const headers = tabGroup.querySelectorAll('.tab-header');
const contents = tabGroup.querySelectorAll('.tab-content');
headers.forEach(header => {
header.addEventListener('click', () => {
const tabIndex = header.getAttribute('data-tab');
// Remove active class from all headers and contents
headers.forEach(h => h.classList.remove('active'));
contents.forEach(c => c.classList.remove('active'));
// Add active class to clicked header and corresponding content
header.classList.add('active');
const activeContent = tabGroup.querySelector(</span><span class="se">\`</span><span class="s2">[data-tab="</span><span class="se">\$</span><span class="s2">{tabIndex}"].tab-content</span><span class="se">\`</span><span class="s2">);
if (activeContent) {
activeContent.classList.add('active');
}
});
});
});
});
`</span><span class="p">;</span>
<span class="c1">// Inject styles and scripts</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nb">document</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">undefined</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">style</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="dl">'</span><span class="s1">style</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">style</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="nx">directiveStyles</span><span class="p">;</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nf">appendChild</span><span class="p">(</span><span class="nx">style</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">script</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="dl">'</span><span class="s1">script</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="nx">directiveInteractions</span><span class="p">;</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nf">appendChild</span><span class="p">(</span><span class="nx">script</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="advanced-extension-systems">Advanced Extension Systems</h2>
<h3 id="plugin-architecture-for-directives">Plugin Architecture for Directives</h3>
<p>Create modular, extensible directive systems:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// markdown-directive-plugin-system.js</span>
<span class="kd">class</span> <span class="nc">MarkdownDirectivePluginSystem</span> <span class="p">{</span>
<span class="nf">constructor</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">plugins</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Map</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">hooks</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">beforeProcessing</span><span class="p">:</span> <span class="p">[],</span>
<span class="na">afterProcessing</span><span class="p">:</span> <span class="p">[],</span>
<span class="na">onDirectiveRegistered</span><span class="p">:</span> <span class="p">[],</span>
<span class="na">onDirectiveProcessed</span><span class="p">:</span> <span class="p">[],</span>
<span class="na">onError</span><span class="p">:</span> <span class="p">[]</span>
<span class="p">};</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processor</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">config</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">debug</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
<span class="na">strictMode</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">allowDynamicRegistration</span><span class="p">:</span> <span class="kc">true</span>
<span class="p">};</span>
<span class="p">}</span>
<span class="nf">registerPlugin</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">plugin</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">plugins</span><span class="p">.</span><span class="nf">has</span><span class="p">(</span><span class="nx">name</span><span class="p">))</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="s2">`Plugin '</span><span class="p">${</span><span class="nx">name</span><span class="p">}</span><span class="s2">' is already registered`</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Validate plugin structure</span>
<span class="k">this</span><span class="p">.</span><span class="nf">validatePlugin</span><span class="p">(</span><span class="nx">plugin</span><span class="p">);</span>
<span class="c1">// Initialize plugin</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nx">plugin</span><span class="p">.</span><span class="nx">init</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">function</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">plugin</span><span class="p">.</span><span class="nf">init</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Register plugin directives</span>
<span class="k">if </span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">directives</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">Object</span><span class="p">.</span><span class="nf">entries</span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">directives</span><span class="p">).</span><span class="nf">forEach</span><span class="p">(([</span><span class="nx">directiveName</span><span class="p">,</span> <span class="nx">processor</span><span class="p">])</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="s2">`</span><span class="p">${</span><span class="nx">name</span><span class="p">}</span><span class="s2">:</span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">`</span><span class="p">,</span> <span class="nx">processor</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="c1">// Register plugin hooks</span>
<span class="k">if </span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">hooks</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">Object</span><span class="p">.</span><span class="nf">entries</span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">hooks</span><span class="p">).</span><span class="nf">forEach</span><span class="p">(([</span><span class="nx">hookName</span><span class="p">,</span> <span class="nx">handler</span><span class="p">])</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">addHook</span><span class="p">(</span><span class="nx">hookName</span><span class="p">,</span> <span class="nx">handler</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">plugins</span><span class="p">.</span><span class="nf">set</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">plugin</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nf">emit</span><span class="p">(</span><span class="dl">'</span><span class="s1">onDirectiveRegistered</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">plugin</span> <span class="p">});</span>
<span class="p">}</span>
<span class="nf">validatePlugin</span><span class="p">(</span><span class="nx">plugin</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nx">plugin</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">object</span><span class="dl">'</span> <span class="o">||</span> <span class="nx">plugin</span> <span class="o">===</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Plugin must be an object</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">name</span> <span class="o">||</span> <span class="k">typeof</span> <span class="nx">plugin</span><span class="p">.</span><span class="nx">name</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Plugin must have a name property</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">version</span> <span class="o">||</span> <span class="k">typeof</span> <span class="nx">plugin</span><span class="p">.</span><span class="nx">version</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Plugin must have a version property</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if </span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">directives</span> <span class="o">&&</span> <span class="k">typeof</span> <span class="nx">plugin</span><span class="p">.</span><span class="nx">directives</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">object</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Plugin directives must be an object</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nf">registerDirective</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">processor</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">processor</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processor</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MarkdownDirectiveProcessor</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processor</span><span class="p">.</span><span class="nf">registerDirective</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">processor</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">addHook</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">handler</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">hooks</span><span class="p">[</span><span class="nx">name</span><span class="p">])</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">hooks</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="p">[];</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">hooks</span><span class="p">[</span><span class="nx">name</span><span class="p">].</span><span class="nf">push</span><span class="p">(</span><span class="nx">handler</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">emit</span><span class="p">(</span><span class="nx">hookName</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">hooks</span><span class="p">[</span><span class="nx">hookName</span><span class="p">])</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">hooks</span><span class="p">[</span><span class="nx">hookName</span><span class="p">].</span><span class="nf">forEach</span><span class="p">(</span><span class="nx">handler</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="nf">handler</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="s2">`Error in hook </span><span class="p">${</span><span class="nx">hookName</span><span class="p">}</span><span class="s2">:`</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nf">processMarkdown</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">emit</span><span class="p">(</span><span class="dl">'</span><span class="s1">beforeProcessing</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="nx">content</span> <span class="p">});</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">processor</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processor</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MarkdownDirectiveProcessor</span><span class="p">();</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">processor</span><span class="p">.</span><span class="nf">processMarkdown</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nf">emit</span><span class="p">(</span><span class="dl">'</span><span class="s1">afterProcessing</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">result</span> <span class="p">});</span>
<span class="k">return</span> <span class="nx">result</span><span class="p">;</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">emit</span><span class="p">(</span><span class="dl">'</span><span class="s1">onError</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="nx">error</span><span class="p">,</span> <span class="nx">content</span> <span class="p">});</span>
<span class="k">throw</span> <span class="nx">error</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nf">getPlugin</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">plugins</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">listPlugins</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="nb">Array</span><span class="p">.</span><span class="k">from</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">plugins</span><span class="p">.</span><span class="nf">keys</span><span class="p">());</span>
<span class="p">}</span>
<span class="nf">unregisterPlugin</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">plugin</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">plugins</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="nx">plugin</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Call plugin cleanup if available</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nx">plugin</span><span class="p">.</span><span class="nx">cleanup</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">function</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">plugin</span><span class="p">.</span><span class="nf">cleanup</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Remove plugin directives</span>
<span class="k">if </span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">directives</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">Object</span><span class="p">.</span><span class="nf">keys</span><span class="p">(</span><span class="nx">plugin</span><span class="p">.</span><span class="nx">directives</span><span class="p">).</span><span class="nf">forEach</span><span class="p">(</span><span class="nx">directiveName</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Remove from processor if available</span>
<span class="k">if </span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">processor</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">processor</span><span class="p">.</span><span class="nx">directiveRegistry</span><span class="p">.</span><span class="k">delete</span><span class="p">(</span><span class="s2">`</span><span class="p">${</span><span class="nx">name</span><span class="p">}</span><span class="s2">:</span><span class="p">${</span><span class="nx">directiveName</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">plugins</span><span class="p">.</span><span class="k">delete</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
<span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Example plugins</span>
<span class="kd">const</span> <span class="nx">chartPlugin</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">charts</span><span class="dl">'</span><span class="p">,</span>
<span class="na">version</span><span class="p">:</span> <span class="dl">'</span><span class="s1">1.0.0</span><span class="dl">'</span><span class="p">,</span>
<span class="na">description</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Adds chart generation directives</span><span class="dl">'</span><span class="p">,</span>
<span class="na">directives</span><span class="p">:</span> <span class="p">{</span>
<span class="dl">'</span><span class="s1">bar-chart</span><span class="dl">'</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseChartData</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">chartId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="k">return</span> <span class="s2">`
<div class="chart-container">
<canvas id="</span><span class="p">${</span><span class="nx">chartId</span><span class="p">}</span><span class="s2">" data-chart-type="bar" data-chart-data='</span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">data</span><span class="p">)}</span><span class="s2">' data-chart-options='</span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">params</span><span class="p">)}</span><span class="s2">'></canvas>
</div>`</span><span class="p">;</span>
<span class="p">},</span>
<span class="dl">'</span><span class="s1">line-chart</span><span class="dl">'</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseChartData</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">chartId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="k">return</span> <span class="s2">`
<div class="chart-container">
<canvas id="</span><span class="p">${</span><span class="nx">chartId</span><span class="p">}</span><span class="s2">" data-chart-type="line" data-chart-data='</span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">data</span><span class="p">)}</span><span class="s2">' data-chart-options='</span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">params</span><span class="p">)}</span><span class="s2">'></canvas>
</div>`</span><span class="p">;</span>
<span class="p">},</span>
<span class="dl">'</span><span class="s1">pie-chart</span><span class="dl">'</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseChartData</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">chartId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="k">return</span> <span class="s2">`
<div class="chart-container">
<canvas id="</span><span class="p">${</span><span class="nx">chartId</span><span class="p">}</span><span class="s2">" data-chart-type="pie" data-chart-data='</span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">data</span><span class="p">)}</span><span class="s2">' data-chart-options='</span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">params</span><span class="p">)}</span><span class="s2">'></canvas>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">parseChartData</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Parse CSV-like data from content</span>
<span class="kd">const</span> <span class="nx">lines</span> <span class="o">=</span> <span class="nx">content</span><span class="p">.</span><span class="nf">trim</span><span class="p">().</span><span class="nf">split</span><span class="p">(</span><span class="dl">'</span><span class="se">\n</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">headers</span> <span class="o">=</span> <span class="nx">lines</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nf">split</span><span class="p">(</span><span class="dl">'</span><span class="s1">,</span><span class="dl">'</span><span class="p">).</span><span class="nf">map</span><span class="p">(</span><span class="nx">h</span> <span class="o">=></span> <span class="nx">h</span><span class="p">.</span><span class="nf">trim</span><span class="p">());</span>
<span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">lines</span><span class="p">.</span><span class="nf">slice</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nf">map</span><span class="p">(</span><span class="nx">line</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">values</span> <span class="o">=</span> <span class="nx">line</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="dl">'</span><span class="s1">,</span><span class="dl">'</span><span class="p">).</span><span class="nf">map</span><span class="p">(</span><span class="nx">v</span> <span class="o">=></span> <span class="nx">v</span><span class="p">.</span><span class="nf">trim</span><span class="p">());</span>
<span class="kd">const</span> <span class="nx">row</span> <span class="o">=</span> <span class="p">{};</span>
<span class="nx">headers</span><span class="p">.</span><span class="nf">forEach</span><span class="p">((</span><span class="nx">header</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">row</span><span class="p">[</span><span class="nx">header</span><span class="p">]</span> <span class="o">=</span> <span class="nf">isNaN</span><span class="p">(</span><span class="nx">values</span><span class="p">[</span><span class="nx">index</span><span class="p">])</span> <span class="p">?</span> <span class="nx">values</span><span class="p">[</span><span class="nx">index</span><span class="p">]</span> <span class="p">:</span> <span class="nf">parseFloat</span><span class="p">(</span><span class="nx">values</span><span class="p">[</span><span class="nx">index</span><span class="p">]);</span>
<span class="p">});</span>
<span class="k">return</span> <span class="nx">row</span><span class="p">;</span>
<span class="p">});</span>
<span class="k">return</span> <span class="p">{</span>
<span class="nx">headers</span><span class="p">,</span>
<span class="nx">data</span>
<span class="p">};</span>
<span class="p">},</span>
<span class="na">generateId</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="dl">'</span><span class="s1">chart-</span><span class="dl">'</span> <span class="o">+</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">random</span><span class="p">().</span><span class="nf">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nf">substr</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">);</span>
<span class="p">},</span>
<span class="na">init</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">system</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Chart plugin initialized</span><span class="dl">'</span><span class="p">);</span>
<span class="c1">// Load Chart.js if not already loaded</span>
<span class="k">if </span><span class="p">(</span><span class="k">typeof</span> <span class="nx">Chart</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">undefined</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">loadChartJS</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">loadChartJS</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">script</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="dl">'</span><span class="s1">script</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">https://cdn.jsdelivr.net/npm/chart.js</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">script</span><span class="p">.</span><span class="nx">onload</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Initialize charts after Chart.js loads</span>
<span class="k">this</span><span class="p">.</span><span class="nf">initializeCharts</span><span class="p">();</span>
<span class="p">};</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nf">appendChild</span><span class="p">(</span><span class="nx">script</span><span class="p">);</span>
<span class="p">},</span>
<span class="na">initializeCharts</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nb">document</span><span class="p">.</span><span class="nf">querySelectorAll</span><span class="p">(</span><span class="dl">'</span><span class="s1">[data-chart-type]</span><span class="dl">'</span><span class="p">).</span><span class="nf">forEach</span><span class="p">(</span><span class="nx">canvas</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">chartType</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nf">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-chart-type</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">chartData</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nf">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-chart-data</span><span class="dl">'</span><span class="p">));</span>
<span class="kd">const</span> <span class="nx">chartOptions</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nf">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-chart-options</span><span class="dl">'</span><span class="p">)</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">{}</span><span class="dl">'</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nf">renderChart</span><span class="p">(</span><span class="nx">canvas</span><span class="p">,</span> <span class="nx">chartType</span><span class="p">,</span> <span class="nx">chartData</span><span class="p">,</span> <span class="nx">chartOptions</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="na">renderChart</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">canvas</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">data</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">ctx</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nf">getContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">2d</span><span class="dl">'</span><span class="p">);</span>
<span class="c1">// Convert data format for Chart.js</span>
<span class="kd">const</span> <span class="nx">chartData</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">labels</span><span class="p">:</span> <span class="nx">data</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="nx">row</span> <span class="o">=></span> <span class="nx">row</span><span class="p">[</span><span class="nx">data</span><span class="p">.</span><span class="nx">headers</span><span class="p">[</span><span class="mi">0</span><span class="p">]]),</span>
<span class="na">datasets</span><span class="p">:</span> <span class="p">[{</span>
<span class="na">label</span><span class="p">:</span> <span class="nx">data</span><span class="p">.</span><span class="nx">headers</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">Data</span><span class="dl">'</span><span class="p">,</span>
<span class="na">data</span><span class="p">:</span> <span class="nx">data</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="nx">row</span> <span class="o">=></span> <span class="nx">row</span><span class="p">[</span><span class="nx">data</span><span class="p">.</span><span class="nx">headers</span><span class="p">[</span><span class="mi">1</span><span class="p">]]),</span>
<span class="na">backgroundColor</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateColors</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">length</span><span class="p">),</span>
<span class="na">borderColor</span><span class="p">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">borderColor</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">#007cba</span><span class="dl">'</span><span class="p">,</span>
<span class="na">borderWidth</span><span class="p">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">borderWidth</span> <span class="o">||</span> <span class="mi">1</span>
<span class="p">}]</span>
<span class="p">};</span>
<span class="k">new</span> <span class="nc">Chart</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> <span class="p">{</span>
<span class="na">type</span><span class="p">:</span> <span class="nx">type</span><span class="p">,</span>
<span class="na">data</span><span class="p">:</span> <span class="nx">chartData</span><span class="p">,</span>
<span class="na">options</span><span class="p">:</span> <span class="p">{</span>
<span class="na">responsive</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">plugins</span><span class="p">:</span> <span class="p">{</span>
<span class="na">title</span><span class="p">:</span> <span class="p">{</span>
<span class="na">display</span><span class="p">:</span> <span class="o">!!</span><span class="nx">options</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
<span class="na">text</span><span class="p">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">title</span> <span class="o">||</span> <span class="dl">''</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="p">...</span><span class="nx">options</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="na">generateColors</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">count</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">colors</span> <span class="o">=</span> <span class="p">[</span>
<span class="dl">'</span><span class="s1">#FF6384</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#36A2EB</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#FFCE56</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#4BC0C0</span><span class="dl">'</span><span class="p">,</span>
<span class="dl">'</span><span class="s1">#9966FF</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#FF9F40</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#FF6384</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#C9CBCF</span><span class="dl">'</span>
<span class="p">];</span>
<span class="k">return</span> <span class="nb">Array</span><span class="p">.</span><span class="k">from</span><span class="p">({</span><span class="na">length</span><span class="p">:</span> <span class="nx">count</span><span class="p">},</span> <span class="p">(</span><span class="nx">_</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span> <span class="nx">colors</span><span class="p">[</span><span class="nx">i</span> <span class="o">%</span> <span class="nx">colors</span><span class="p">.</span><span class="nx">length</span><span class="p">]);</span>
<span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">interactivePlugin</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">interactive</span><span class="dl">'</span><span class="p">,</span>
<span class="na">version</span><span class="p">:</span> <span class="dl">'</span><span class="s1">1.0.0</span><span class="dl">'</span><span class="p">,</span>
<span class="na">description</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Adds interactive content directives</span><span class="dl">'</span><span class="p">,</span>
<span class="na">directives</span><span class="p">:</span> <span class="p">{</span>
<span class="dl">'</span><span class="s1">accordion</span><span class="dl">'</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">accordionId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">items</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">parseAccordionItems</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">html</span> <span class="o">=</span> <span class="s2">`<div class="accordion" id="</span><span class="p">${</span><span class="nx">accordionId</span><span class="p">}</span><span class="s2">">`</span><span class="p">;</span>
<span class="nx">items</span><span class="p">.</span><span class="nf">forEach</span><span class="p">((</span><span class="nx">item</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">itemId</span> <span class="o">=</span> <span class="s2">`</span><span class="p">${</span><span class="nx">accordionId</span><span class="p">}</span><span class="s2">-item-</span><span class="p">${</span><span class="nx">index</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">expanded</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">expanded</span> <span class="o">&&</span> <span class="nx">params</span><span class="p">.</span><span class="nx">expanded</span><span class="p">.</span><span class="nf">includes</span><span class="p">(</span><span class="nx">index</span><span class="p">.</span><span class="nf">toString</span><span class="p">());</span>
<span class="nx">html</span> <span class="o">+=</span> <span class="s2">`
<div class="accordion-item">
<div class="accordion-header">
<button class="accordion-button</span><span class="p">${</span><span class="nx">expanded</span> <span class="p">?</span> <span class="dl">''</span> <span class="p">:</span> <span class="dl">'</span><span class="s1"> collapsed</span><span class="dl">'</span><span class="p">}</span><span class="s2">"
type="button"
data-toggle="collapse"
data-target="#</span><span class="p">${</span><span class="nx">itemId</span><span class="p">}</span><span class="s2">"
aria-expanded="</span><span class="p">${</span><span class="nx">expanded</span><span class="p">}</span><span class="s2">"
aria-controls="</span><span class="p">${</span><span class="nx">itemId</span><span class="p">}</span><span class="s2">">
</span><span class="p">${</span><span class="nx">item</span><span class="p">.</span><span class="nx">title</span><span class="p">}</span><span class="s2">
</button>
</div>
<div id="</span><span class="p">${</span><span class="nx">itemId</span><span class="p">}</span><span class="s2">" class="accordion-collapse collapse</span><span class="p">${</span><span class="nx">expanded</span> <span class="p">?</span> <span class="dl">'</span><span class="s1"> show</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">" data-parent="#</span><span class="p">${</span><span class="nx">accordionId</span><span class="p">}</span><span class="s2">">
<div class="accordion-body">
</span><span class="p">${</span><span class="nx">item</span><span class="p">.</span><span class="nx">content</span><span class="p">}</span><span class="s2">
</div>
</div>
</div>`</span><span class="p">;</span>
<span class="p">});</span>
<span class="nx">html</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1"></div></span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">html</span><span class="p">;</span>
<span class="p">},</span>
<span class="dl">'</span><span class="s1">collapsible</span><span class="dl">'</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">collapsibleId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">title</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">Click to expand</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">expanded</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">expanded</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">true</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<div class="collapsible">
<button class="collapsible-toggle</span><span class="p">${</span><span class="nx">expanded</span> <span class="p">?</span> <span class="dl">'</span><span class="s1"> expanded</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">"
data-target="#</span><span class="p">${</span><span class="nx">collapsibleId</span><span class="p">}</span><span class="s2">"
aria-expanded="</span><span class="p">${</span><span class="nx">expanded</span><span class="p">}</span><span class="s2">">
<span class="toggle-icon"></span><span class="p">${</span><span class="nx">expanded</span> <span class="p">?</span> <span class="dl">'</span><span class="s1">▼</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">'</span><span class="s1">▶</span><span class="dl">'</span><span class="p">}</span><span class="s2"></span>
</span><span class="p">${</span><span class="nx">title</span><span class="p">}</span><span class="s2">
</button>
<div id="</span><span class="p">${</span><span class="nx">collapsibleId</span><span class="p">}</span><span class="s2">" class="collapsible-content</span><span class="p">${</span><span class="nx">expanded</span> <span class="p">?</span> <span class="dl">'</span><span class="s1"> show</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">">
<div class="collapsible-body">
</span><span class="p">${</span><span class="nx">content</span><span class="p">}</span><span class="s2">
</div>
</div>
</div>`</span><span class="p">;</span>
<span class="p">},</span>
<span class="dl">'</span><span class="s1">modal</span><span class="dl">'</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">params</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">context</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">modalId</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">generateId</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">title</span> <span class="o">||</span> <span class="dl">''</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">triggerText</span> <span class="o">=</span> <span class="nx">params</span><span class="p">.</span><span class="nx">trigger</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">Open Modal</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="s2">`
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#</span><span class="p">${</span><span class="nx">modalId</span><span class="p">}</span><span class="s2">">
</span><span class="p">${</span><span class="nx">triggerText</span><span class="p">}</span><span class="s2">
</button>
<div class="modal fade" id="</span><span class="p">${</span><span class="nx">modalId</span><span class="p">}</span><span class="s2">" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
</span><span class="p">${</span><span class="nx">title</span> <span class="p">?</span> <span class="s2">`<div class="modal-header">
<h5 class="modal-title"></span><span class="p">${</span><span class="nx">title</span><span class="p">}</span><span class="s2"></h5>
<button type="button" class="btn-close" data-dismiss="modal"></button>
</div>`</span> <span class="p">:</span> <span class="dl">''</span><span class="p">}</span><span class="s2">
<div class="modal-body">
</span><span class="p">${</span><span class="nx">content</span><span class="p">}</span><span class="s2">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>`</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">parseAccordionItems</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">sections</span> <span class="o">=</span> <span class="nx">content</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="sr">/^## /m</span><span class="p">).</span><span class="nf">filter</span><span class="p">(</span><span class="nx">section</span> <span class="o">=></span> <span class="nx">section</span><span class="p">.</span><span class="nf">trim</span><span class="p">());</span>
<span class="k">return</span> <span class="nx">sections</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="nx">section</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">lines</span> <span class="o">=</span> <span class="nx">section</span><span class="p">.</span><span class="nf">trim</span><span class="p">().</span><span class="nf">split</span><span class="p">(</span><span class="dl">'</span><span class="se">\n</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">lines</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
<span class="kd">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="nx">lines</span><span class="p">.</span><span class="nf">slice</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nf">join</span><span class="p">(</span><span class="dl">'</span><span class="se">\n</span><span class="dl">'</span><span class="p">).</span><span class="nf">trim</span><span class="p">();</span>
<span class="k">return</span> <span class="p">{</span> <span class="nx">title</span><span class="p">,</span> <span class="nx">content</span> <span class="p">};</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="na">generateId</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="dl">'</span><span class="s1">interactive-</span><span class="dl">'</span> <span class="o">+</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">random</span><span class="p">().</span><span class="nf">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nf">substr</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">);</span>
<span class="p">},</span>
<span class="na">init</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">system</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Interactive plugin initialized</span><span class="dl">'</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nf">addEventListeners</span><span class="p">();</span>
<span class="p">},</span>
<span class="na">addEventListeners</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nb">document</span><span class="p">.</span><span class="nf">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">click</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Handle collapsible toggles</span>
<span class="k">if </span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nf">matches</span><span class="p">(</span><span class="dl">'</span><span class="s1">.collapsible-toggle</span><span class="dl">'</span><span class="p">))</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">toggleCollapsible</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Handle accordion buttons</span>
<span class="k">if </span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nf">matches</span><span class="p">(</span><span class="dl">'</span><span class="s1">.accordion-button</span><span class="dl">'</span><span class="p">))</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">toggleAccordion</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="na">toggleCollapsible</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">button</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">targetId</span> <span class="o">=</span> <span class="nx">button</span><span class="p">.</span><span class="nf">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-target</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="nx">targetId</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">icon</span> <span class="o">=</span> <span class="nx">button</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">.toggle-icon</span><span class="dl">'</span><span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="nx">content</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">contains</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">))</span> <span class="p">{</span>
<span class="nx">content</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="dl">'</span><span class="s1">expanded</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">aria-expanded</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">false</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">icon</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">▶</span><span class="dl">'</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">content</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="dl">'</span><span class="s1">expanded</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">aria-expanded</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">true</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">icon</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">▼</span><span class="dl">'</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">toggleAccordion</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">button</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">targetId</span> <span class="o">=</span> <span class="nx">button</span><span class="p">.</span><span class="nf">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-target</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="nx">targetId</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">accordion</span> <span class="o">=</span> <span class="nx">button</span><span class="p">.</span><span class="nf">closest</span><span class="p">(</span><span class="dl">'</span><span class="s1">.accordion</span><span class="dl">'</span><span class="p">);</span>
<span class="c1">// Close other items in the same accordion</span>
<span class="nx">accordion</span><span class="p">.</span><span class="nf">querySelectorAll</span><span class="p">(</span><span class="dl">'</span><span class="s1">.accordion-collapse.show</span><span class="dl">'</span><span class="p">).</span><span class="nf">forEach</span><span class="p">(</span><span class="nx">item</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="nx">item</span> <span class="o">!==</span> <span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">item</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">otherButton</span> <span class="o">=</span> <span class="nx">accordion</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="s2">`[data-target="#</span><span class="p">${</span><span class="nx">item</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span><span class="s2">"]`</span><span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="nx">otherButton</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">otherButton</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="dl">'</span><span class="s1">collapsed</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">otherButton</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">aria-expanded</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">false</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="c1">// Toggle current item</span>
<span class="k">if </span><span class="p">(</span><span class="nx">content</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">contains</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">))</span> <span class="p">{</span>
<span class="nx">content</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="dl">'</span><span class="s1">collapsed</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">aria-expanded</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">false</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">content</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="dl">'</span><span class="s1">show</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="dl">'</span><span class="s1">collapsed</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">button</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">aria-expanded</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">true</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="c1">// Initialize plugin system</span>
<span class="kd">const</span> <span class="nx">pluginSystem</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MarkdownDirectivePluginSystem</span><span class="p">();</span>
<span class="c1">// Register plugins</span>
<span class="nx">pluginSystem</span><span class="p">.</span><span class="nf">registerPlugin</span><span class="p">(</span><span class="dl">'</span><span class="s1">charts</span><span class="dl">'</span><span class="p">,</span> <span class="nx">chartPlugin</span><span class="p">);</span>
<span class="nx">pluginSystem</span><span class="p">.</span><span class="nf">registerPlugin</span><span class="p">(</span><span class="dl">'</span><span class="s1">interactive</span><span class="dl">'</span><span class="p">,</span> <span class="nx">interactivePlugin</span><span class="p">);</span>
<span class="c1">// Export for use</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">markdownPluginSystem</span> <span class="o">=</span> <span class="nx">pluginSystem</span><span class="p">;</span>
</code></pre></div></div>
<h2 id="static-site-generator-integration">Static Site Generator Integration</h2>
<h3 id="jekyll-liquid-extension">Jekyll Liquid Extension</h3>
<p>Create Jekyll-compatible directive processing:</p>
<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<!-- _plugins/directive_processor.rb -->
require 'liquid'
module Jekyll
class DirectiveProcessor < Liquid::Block
def initialize(tag_name, params, tokens)
super
@directive_name = tag_name
@params = parse_params(params)
end
def render(context)
content = super
case @directive_name
when 'info'
render_info_block(content, @params)
when 'warning'
render_warning_block(content, @params)
when 'code_example'
render_code_example(content, @params)
when 'definition'
render_definition(content, @params)
else
content
end
end
private
def parse_params(param_string)
params = {}
return params if param_string.nil?
# Parse key="value" pairs
param_string.scan(/(\w+)="([^"]*)"/) do |key, value|
params[key] = value
end
# Parse key=value pairs
param_string.scan(/(\w+)=(\w+)/) do |key, value|
params[key] = value unless params.key?(key)
end
params
end
def render_info_block(content, params)
title = params['title'] || ''
icon = params['icon'] || 'ℹ️'
<<~HTML
<div class="directive-block directive-info">
#{title.empty? ? '' : %(<div class="directive-header">
<span class="directive-icon">#{icon}</span>
<span class="directive-title">#{title}</span>
</div>)}
<div class="directive-content">
#{markdownify(content)}
</div>
</div>
HTML
end
def render_warning_block(content, params)
title = params['title'] || 'Warning'
icon = params['icon'] || '⚠️'
<<~HTML
<div class="directive-block directive-warning">
<div class="directive-header">
<span class="directive-icon">#{icon}</span>
<span class="directive-title">#{title}</span>
</div>
<div class="directive-content">
#{markdownify(content)}
</div>
</div>
HTML
end
def render_code_example(content, params)
language = params['language'] || 'text'
filename = params['filename'] || ''
<<~HTML
<div class="directive-block directive-code-example">
#{filename.empty? ? '' : %(<div class="code-filename">#{filename}</div>)}
<div class="code-container">
<pre class="code-block language-#{language}"><code>#{content.strip}</code></pre>
</div>
</div>
HTML
end
def render_definition(content, params)
term = params['term'] || ''
<<~HTML
<div class="directive-block directive-definition">
<div class="definition-term">#{term}</div>
<div class="definition-content">
#{markdownify(content)}
</div>
</div>
HTML
end
def markdownify(content)
Jekyll::Converters::Markdown.new({}).convert(content)
end
end
end
# Register directive tags
Liquid::Template.register_tag('info', Jekyll::DirectiveProcessor)
Liquid::Template.register_tag('warning', Jekyll::DirectiveProcessor)
Liquid::Template.register_tag('code_example', Jekyll::DirectiveProcessor)
Liquid::Template.register_tag('definition', Jekyll::DirectiveProcessor)
<!-- Usage in Markdown files: -->
<span class="cp">{%</span><span class="w"> </span><span class="nt">info</span><span class="w"> </span><span class="na">title</span><span class="o">=</span><span class="s2">"Important Information"</span><span class="w"> </span><span class="cp">%}</span>
This is important information that readers should notice.
It supports **markdown formatting** and `inline code`.
<span class="cp">{%</span><span class="w"> </span><span class="nt">endinfo</span><span class="w"> </span><span class="cp">%}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">warning</span><span class="w"> </span><span class="na">title</span><span class="o">=</span><span class="s2">"Critical Warning"</span><span class="w"> </span><span class="cp">%}</span>
This is a critical warning with important safety information.
<span class="cp">{%</span><span class="w"> </span><span class="nt">endwarning</span><span class="w"> </span><span class="cp">%}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">code_example</span><span class="w"> </span><span class="na">language</span><span class="o">=</span><span class="s2">"javascript"</span><span class="w"> </span><span class="na">filename</span><span class="o">=</span><span class="s2">"example.js"</span><span class="w"> </span><span class="cp">%}</span>
function exampleFunction() {
console.log("This is an example");
}
<span class="cp">{%</span><span class="w"> </span><span class="nt">endcode_example</span><span class="w"> </span><span class="cp">%}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">definition</span><span class="w"> </span><span class="na">term</span><span class="o">=</span><span class="s2">"API Endpoint"</span><span class="w"> </span><span class="cp">%}</span>
An API endpoint is a specific URL where an API can be accessed by a client application.
<span class="cp">{%</span><span class="w"> </span><span class="nt">enddefinition</span><span class="w"> </span><span class="cp">%}</span>
</code></pre></div></div>
<h3 id="hugo-shortcode-system">Hugo Shortcode System</h3>
<p>Advanced shortcode implementations for Hugo:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// layouts/shortcodes/directive.html</span>
<span class="p">{{</span> <span class="err">$</span><span class="k">type</span> <span class="o">:=</span> <span class="o">.</span><span class="n">Get</span> <span class="s">"type"</span> <span class="o">|</span> <span class="k">default</span> <span class="s">"info"</span> <span class="p">}}</span>
<span class="p">{{</span> <span class="err">$</span><span class="n">title</span> <span class="o">:=</span> <span class="o">.</span><span class="n">Get</span> <span class="s">"title"</span> <span class="p">}}</span>
<span class="p">{{</span> <span class="err">$</span><span class="n">icon</span> <span class="o">:=</span> <span class="o">.</span><span class="n">Get</span> <span class="s">"icon"</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-block directive-{{ $type }}"</span><span class="o">></span>
<span class="p">{{</span> <span class="k">if</span> <span class="err">$</span><span class="n">title</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-header"</span><span class="o">></span>
<span class="p">{{</span> <span class="k">if</span> <span class="err">$</span><span class="n">icon</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">span</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-icon"</span><span class="o">></span><span class="p">{{</span> <span class="err">$</span><span class="n">icon</span> <span class="p">}}</span><span class="o"></</span><span class="n">span</span><span class="o">></span>
<span class="p">{{</span> <span class="k">else</span> <span class="p">}}</span>
<span class="p">{{</span> <span class="k">if</span> <span class="n">eq</span> <span class="err">$</span><span class="k">type</span> <span class="s">"info"</span> <span class="p">}}</span><span class="o"><</span><span class="n">span</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-icon"</span><span class="o">></span><span class="n">ℹ</span><span class="err">️</span><span class="o"></</span><span class="n">span</span><span class="o">></span><span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="p">{{</span> <span class="k">if</span> <span class="n">eq</span> <span class="err">$</span><span class="k">type</span> <span class="s">"warning"</span> <span class="p">}}</span><span class="o"><</span><span class="n">span</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-icon"</span><span class="o">></span><span class="err">⚠️</span><span class="o"></</span><span class="n">span</span><span class="o">></span><span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="p">{{</span> <span class="k">if</span> <span class="n">eq</span> <span class="err">$</span><span class="k">type</span> <span class="s">"example"</span> <span class="p">}}</span><span class="o"><</span><span class="n">span</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-icon"</span><span class="o">></span><span class="err">💡</span><span class="o"></</span><span class="n">span</span><span class="o">></span><span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">span</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-title"</span><span class="o">></span><span class="p">{{</span> <span class="err">$</span><span class="n">title</span> <span class="p">}}</span><span class="o"></</span><span class="n">span</span><span class="o">></span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-content"</span><span class="o">></span>
<span class="p">{{</span> <span class="o">.</span><span class="n">Inner</span> <span class="o">|</span> <span class="n">markdownify</span> <span class="p">}}</span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
</code></pre></div></div>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// layouts/shortcodes/tabs.html</span>
<span class="p">{{</span> <span class="err">$</span><span class="n">tabsId</span> <span class="o">:=</span> <span class="n">printf</span> <span class="s">"tabs-%d"</span> <span class="p">(</span><span class="n">rand</span> <span class="m">1000</span><span class="p">)</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"directive-tabs"</span> <span class="n">data</span><span class="o">-</span><span class="n">tabs</span><span class="o">-</span><span class="n">id</span><span class="o">=</span><span class="s">"{{ $tabsId }}"</span><span class="o">></span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"tab-headers"</span><span class="o">></span>
<span class="p">{{</span> <span class="k">range</span> <span class="err">$</span><span class="n">index</span><span class="p">,</span> <span class="err">$</span><span class="n">tab</span> <span class="o">:=</span> <span class="o">.</span><span class="n">Params</span><span class="o">.</span><span class="n">tabs</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">button</span> <span class="n">class</span><span class="o">=</span><span class="s">"tab-header{{ if eq $index 0 }} active{{ end }}"</span> <span class="n">data</span><span class="o">-</span><span class="n">tab</span><span class="o">=</span><span class="s">"{{ $index }}"</span><span class="o">></span>
<span class="p">{{</span> <span class="err">$</span><span class="n">tab</span><span class="o">.</span><span class="n">title</span> <span class="p">}}</span>
<span class="o"></</span><span class="n">button</span><span class="o">></span>
<span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"tab-contents"</span><span class="o">></span>
<span class="p">{{</span> <span class="k">range</span> <span class="err">$</span><span class="n">index</span><span class="p">,</span> <span class="err">$</span><span class="n">tab</span> <span class="o">:=</span> <span class="o">.</span><span class="n">Params</span><span class="o">.</span><span class="n">tabs</span> <span class="p">}}</span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s">"tab-content{{ if eq $index 0 }} active{{ end }}"</span> <span class="n">data</span><span class="o">-</span><span class="n">tab</span><span class="o">=</span><span class="s">"{{ $index }}"</span><span class="o">></span>
<span class="p">{{</span> <span class="err">$</span><span class="n">tab</span><span class="o">.</span><span class="n">content</span> <span class="o">|</span> <span class="n">markdownify</span> <span class="p">}}</span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="p">{{</span> <span class="n">end</span> <span class="p">}}</span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
</code></pre></div></div>
<p>Usage in Hugo Markdown:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{{<span class="nt"><</span> <span class="nt">directive</span> <span class="na">type=</span><span class="s">"info"</span> <span class="na">title=</span><span class="s">"Getting Started"</span> <span class="nt">></span>}}
This is an information block with <span class="gs">**markdown**</span> support.
{{<span class="nt"><</span> <span class="err">/</span><span class="na">directive</span> <span class="nt">></span>}}
{{<span class="nt"><</span> <span class="nt">directive</span> <span class="na">type=</span><span class="s">"warning"</span> <span class="na">title=</span><span class="s">"Important Notice"</span> <span class="nt">></span>}}
This is a warning with critical information.
{{<span class="nt"><</span> <span class="err">/</span><span class="na">directive</span> <span class="nt">></span>}}
{{<span class="nt"><</span> <span class="nt">tabs</span> <span class="nt">></span>}}
{{<span class="nt"><</span> <span class="nt">tab</span> <span class="na">title=</span><span class="s">"JavaScript"</span> <span class="nt">></span>}}
<span class="p">```</span><span class="nl">javascript
</span><span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">Hello World</span><span class="dl">"</span><span class="p">);</span>
</code></pre></div></div>
<p>{{< /tab >}}<br />
{{< tab title=”Python” >}}</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Hello World</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div>
<p>{{< /tab >}}<br />
{{< /tabs >}}</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
## Security and Performance Considerations
### Secure Directive Processing
Implement security measures for custom directives:
```javascript
// secure-directive-processor.js - Security-focused directive processing
class SecureDirectiveProcessor {
constructor(options = {}) {
this.securityConfig = {
allowedTags: ['div', 'span', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'code', 'pre', 'strong', 'em'],
allowedAttributes: ['class', 'id', 'data-*', 'aria-*'],
allowedProtocols: ['http:', 'https:', 'mailto:'],
maxDirectiveDepth: 5,
maxContentLength: 50000,
sanitizeHTML: true,
...options.security
};
this.performanceConfig = {
maxDirectivesPerDocument: 500,
processingTimeout: 5000,
enableCaching: true,
cacheSize: 1000,
...options.performance
};
this.cache = new Map();
this.stats = {
processed: 0,
cached: 0,
errors: 0,
securityViolations: 0
};
}
processContent(content) {
try {
// Pre-processing security checks
if (!this.validateContent(content)) {
throw new Error('Content validation failed');
}
// Check cache first
const cacheKey = this.generateCacheKey(content);
if (this.performanceConfig.enableCaching && this.cache.has(cacheKey)) {
this.stats.cached++;
return this.cache.get(cacheKey);
}
// Process with timeout
const result = this.processWithTimeout(content);
// Cache result
if (this.performanceConfig.enableCaching) {
this.cacheResult(cacheKey, result);
}
this.stats.processed++;
return result;
} catch (error) {
this.stats.errors++;
console.error('Directive processing error:', error);
return this.createErrorResponse(error);
}
}
validateContent(content) {
// Length validation
if (content.length > this.securityConfig.maxContentLength) {
this.stats.securityViolations++;
return false;
}
// Check for suspicious patterns
const suspiciousPatterns = [
/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
/javascript:/gi,
/on\w+\s*=/gi,
/data:(?!image\/[png|jpg|jpeg|gif|svg])/gi
];
for (const pattern of suspiciousPatterns) {
if (pattern.test(content)) {
this.stats.securityViolations++;
return false;
}
}
return true;
}
processWithTimeout(content) {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error('Processing timeout exceeded'));
}, this.performanceConfig.processingTimeout);
try {
const result = this.processDirectives(content);
clearTimeout(timeout);
resolve(result);
} catch (error) {
clearTimeout(timeout);
reject(error);
}
});
}
processDirectives(content) {
// Count directives to prevent abuse
const directiveCount = (content.match(/:::\w+/g) || []).length;
if (directiveCount > this.performanceConfig.maxDirectivesPerDocument) {
throw new Error('Too many directives in document');
}
// Process with depth tracking
return this.processWithDepthTracking(content, 0);
}
processWithDepthTracking(content, depth) {
if (depth > this.securityConfig.maxDirectiveDepth) {
throw new Error('Maximum directive nesting depth exceeded');
}
// Process directives at current level
const directivePattern = /:::(\w+)(?:\s+([^\n]*))?\n([\s\S]*?)\n:::/g;
return content.replace(directivePattern, (match, type, params, innerContent) => {
// Validate directive type
if (!this.isAllowedDirective(type)) {
this.stats.securityViolations++;
return this.createSecurityError(`Directive type '${type}' not allowed`);
}
// Sanitize parameters
const sanitizedParams = this.sanitizeParameters(params);
// Process nested content
const processedContent = this.processWithDepthTracking(innerContent, depth + 1);
// Generate directive HTML
const html = this.generateDirectiveHTML(type, sanitizedParams, processedContent);
// Sanitize output HTML
return this.sanitizeHTML(html);
});
}
isAllowedDirective(type) {
const allowedDirectives = [
'info', 'warning', 'example', 'definition',
'code-example', 'tab-group', 'tab'
];
return allowedDirectives.includes(type);
}
sanitizeParameters(paramString) {
if (!paramString) return {};
const params = {};
const paramPattern = /(\w+)="([^"]*)"/g;
let match;
while ((match = paramPattern.exec(paramString)) !== null) {
const key = match[1];
const value = match[2];
// Validate parameter name
if (!/^\w+$/.test(key)) {
continue;
}
// Sanitize parameter value
params[key] = this.sanitizeParameterValue(value);
}
return params;
}
sanitizeParameterValue(value) {
// Remove potentially dangerous content
return value
.replace(/[<>'"]/g, '')
.replace(/javascript:/gi, '')
.replace(/on\w+/gi, '')
.substring(0, 200); // Limit length
}
sanitizeHTML(html) {
if (!this.securityConfig.sanitizeHTML) {
return html;
}
// Basic HTML sanitization
const div = document.createElement('div');
div.innerHTML = html;
// Remove disallowed tags
this.removeDisallowedElements(div);
// Sanitize attributes
this.sanitizeAttributes(div);
return div.innerHTML;
}
removeDisallowedElements(container) {
const elements = container.querySelectorAll('*');
elements.forEach(element => {
if (!this.securityConfig.allowedTags.includes(element.tagName.toLowerCase())) {
element.remove();
}
});
}
sanitizeAttributes(container) {
const elements = container.querySelectorAll('*');
elements.forEach(element => {
const attributesToRemove = [];
for (const attr of element.attributes) {
if (!this.isAllowedAttribute(attr.name)) {
attributesToRemove.push(attr.name);
} else if (attr.name === 'href' || attr.name === 'src') {
if (!this.isAllowedURL(attr.value)) {
attributesToRemove.push(attr.name);
}
}
}
attributesToRemove.forEach(attrName => {
element.removeAttribute(attrName);
});
});
}
isAllowedAttribute(attrName) {
return this.securityConfig.allowedAttributes.some(allowed => {
if (allowed.endsWith('*')) {
return attrName.startsWith(allowed.slice(0, -1));
}
return attrName === allowed;
});
}
isAllowedURL(url) {
try {
const parsed = new URL(url, window.location.href);
return this.securityConfig.allowedProtocols.includes(parsed.protocol);
} catch {
return false;
}
}
generateDirectiveHTML(type, params, content) {
// Use safe HTML generation methods
switch (type) {
case 'info':
return this.generateInfoDirective(params, content);
case 'warning':
return this.generateWarningDirective(params, content);
default:
return content;
}
}
generateInfoDirective(params, content) {
const title = params.title || '';
return `
<div class="directive-block directive-info">
${title ? `<div class="directive-header">
<span class="directive-title">${this.escapeHTML(title)}</span>
</div>` : ''}
<div class="directive-content">${content}</div>
</div>`;
}
generateWarningDirective(params, content) {
const title = params.title || 'Warning';
return `
<div class="directive-block directive-warning">
<div class="directive-header">
<span class="directive-title">${this.escapeHTML(title)}</span>
</div>
<div class="directive-content">${content}</div>
</div>`;
}
escapeHTML(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
generateCacheKey(content) {
// Simple hash function for cache keys
let hash = 0;
for (let i = 0; i < content.length; i++) {
const char = content.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash.toString();
}
cacheResult(key, result) {
if (this.cache.size >= this.performanceConfig.cacheSize) {
// Remove oldest entry
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, result);
}
createErrorResponse(error) {
return `<div class="directive-error">Error processing directives: ${this.escapeHTML(error.message)}</div>`;
}
createSecurityError(message) {
return `<div class="directive-security-error">Security violation: ${this.escapeHTML(message)}</div>`;
}
getStats() {
return {
...this.stats,
cacheSize: this.cache.size,
cacheHitRate: this.stats.cached / (this.stats.processed + this.stats.cached)
};
}
clearCache() {
this.cache.clear();
}
}
// Initialize secure processor
const secureProcessor = new SecureDirectiveProcessor({
security: {
allowedTags: ['div', 'span', 'p', 'code', 'pre', 'strong', 'em', 'h1', 'h2', 'h3', 'h4'],
allowedAttributes: ['class', 'id', 'data-*', 'aria-*'],
maxDirectiveDepth: 3,
maxContentLength: 100000
},
performance: {
maxDirectivesPerDocument: 200,
processingTimeout: 3000,
enableCaching: true
}
});
</code></pre></div></div>
<h2 id="integration-with-modern-documentation-systems">Integration with Modern Documentation Systems</h2>
<p>Custom directive systems integrate seamlessly with comprehensive content management platforms. When combined with <a href="https://blog.markdowntools.com/posts/markdown-automation-workflows-complete-guide">automation workflows and content processing</a>, custom directives enable sophisticated build processes that can validate content, generate interactive components, and maintain consistency across large documentation projects.</p>
<p>For advanced content architectures, directive systems work effectively with <a href="https://blog.markdowntools.com/posts/markdown-progressive-web-app-documentation-complete-guide">Progressive Web App documentation platforms</a> to provide offline functionality, cached interactive components, and enhanced user experiences for technical documentation systems.</p>
<p>When building comprehensive documentation ecosystems, custom directives complement <a href="https://blog.markdowntools.com/posts/markdown-table-performance-optimization-for-large-datasets">advanced table management and data presentation systems</a> by enabling contextual content blocks, interactive data visualizations, and sophisticated information organization patterns.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Custom Markdown directives and block extensions transform static content into dynamic, interactive documentation platforms that maintain Markdown’s simplicity while providing powerful extensibility. By implementing systematic directive processors, creating reusable content components, and establishing secure extension architectures, technical teams can build sophisticated content management systems that scale with project requirements while maintaining consistency and performance.</p>
<p>The key to successful directive implementation lies in balancing functionality with security, establishing clear syntax conventions, and creating maintainable processing systems that can evolve with changing requirements. Whether you’re building technical documentation, educational content, or interactive guides, the directive techniques covered in this guide provide the foundation for creating rich, engaging content experiences.</p>
<p>Remember to prioritize security in directive processing, implement comprehensive error handling, and establish clear guidelines for directive usage within your team. With proper implementation of custom Markdown directive systems, your documentation can achieve new levels of interactivity and user engagement while preserving the clean, readable format that makes Markdown an effective content creation tool.</p>
</div><a class="u-url" href="/posts/markdown-custom-directives-block-extensions-complete-guide" hidden></a>
</article>
Hugo configuration for enhanced anchor processing:
# config.yml - Hugo anchor link configuration
markup:
goldmark:
renderer:
unsafe: true
parser:
autoHeadingID: true
autoHeadingIDType: github
extensions:
linkify: true
strikethrough: true
table: true
taskList: true
tableOfContents:
startLevel: 2
endLevel: 4
ordered: false
params:
tocTitle: "Table of Contents"
enableSmoothScroll: true
headingAnchorType: "link" # or "hash"
GitBook Integration
Custom anchor link plugin for GitBook documentation:
// gitbook-anchor-plugin.js
module.exports = {
hooks: {
"page:before": function(page) {
// Process content to add custom anchor handling
let content = page.content;
// Add heading IDs and anchor links
content = content.replace(/^(#{1,6})\s+(.+)$/gm, function(match, hashes, title) {
const level = hashes.length;
const id = title.toLowerCase()
.replace(/[^\w\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '');
return `${hashes} ${title} {#${id}}
<a href="#${id}" class="heading-anchor" aria-label="Link to ${title}">🔗</a>`;
});
page.content = content;
return page;
},
"page:after": function(page) {
// Add navigation enhancement script
page.content += `
<script>
document.addEventListener('DOMContentLoaded', function() {
// Auto-generate table of contents
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
if (headings.length > 2) {
const toc = generateTableOfContents(headings);
const firstHeading = headings[0];
if (firstHeading) {
firstHeading.parentNode.insertBefore(toc, firstHeading);
}
}
function generateTableOfContents(headings) {
const tocContainer = document.createElement('div');
tocContainer.className = 'table-of-contents';
tocContainer.innerHTML = '<h3>Table of Contents</h3><ul class="toc-list"></ul>';
const tocList = tocContainer.querySelector('.toc-list');
headings.forEach(heading => {
if (heading.id) {
const listItem = document.createElement('li');
const link = document.createElement('a');
link.href = '#' + heading.id;
link.textContent = heading.textContent.replace('🔗', '').trim();
link.className = 'toc-link toc-level-' + heading.tagName.charAt(1);
listItem.appendChild(link);
tocList.appendChild(listItem);
}
});
return tocContainer;
}
});
</script>`;
return page;
}
}
};
Advanced Cross-Document Navigation
Multi-Document Linking Strategies
Creating comprehensive navigation across multiple Markdown documents:
# Cross-Document Navigation Patterns
## Internal Document Structure
### Standard Navigation Links
- [Previous Section](./setup.md#installation)
- [Next Section](./configuration.md#basic-setup)
- [Related Topic](../advanced/performance.md#optimization)
### Breadcrumb Navigation
<div class="breadcrumb-nav">
<ul>
<li><a href="../index.md">Documentation Home</a></li>
<li><a href="./index.md">User Guide</a></li>
<li><a href="#getting-started">Getting Started</a></li>
</ul>
</div>
## Cross-Reference Patterns
### API Documentation Cross-References
For authentication details, see [Authentication Guide](../api/auth.md#oauth-flow).
The complete endpoint list is available in the [API Reference](../api/endpoints.md#user-management).
### Tutorial Progression
This builds on concepts from:
- [Basic Setup](./setup.md#initial-configuration)
- [User Management](./users.md#creating-users)
Next, you'll learn about:
- [Advanced Configuration](./advanced-config.md)
- [Troubleshooting Common Issues](./troubleshooting.md#common-problems)
### Code Example References
```javascript
// See full implementation in examples/auth.js#L45-L67
function authenticateUser(credentials) {
// Simplified version - see link above for complete code
return validateCredentials(credentials);
}
Reference: Complete Authentication Example
Navigation Helpers
Section Quick Links
Quick Navigation
Related Articles
External Reference Links
Link Validation and Management
Automated system for validating and managing anchor links:
// link-validator.js - Comprehensive anchor link validation
class AnchorLinkValidator {
constructor(options = {}) {
this.options = {
checkExternalLinks: false,
validateFragments: true,
reportBrokenLinks: true,
autoFixLinks: false,
ignorePrefixes: ['http', 'https', 'mailto', 'tel'],
...options
};
this.linkReport = {
total: 0,
valid: 0,
broken: 0,
missing: 0,
external: 0,
details: []
};
this.anchorMap = new Map();
}
validateDocument(content, baseURL = '') {
// Build map of available anchors
this.buildAnchorMap(content);
// Find all links
const links = this.extractLinks(content);
// Validate each link
links.forEach(link => {
this.validateLink(link, baseURL);
});
return this.generateReport();
}
buildAnchorMap(content) {
this.anchorMap.clear();
// Find heading anchors
const headingRegex = /^(#{1,6})\s+(.+?)(?:\s*\{#([^}]+)\})?$/gm;
let match;
while ((match = headingRegex.exec(content)) !== null) {
const level = match[1].length;
const text = match[2].trim();
const customId = match[3];
// Generate automatic ID if no custom ID
const id = customId || this.generateHeadingId(text);
this.anchorMap.set(id, {
type: 'heading',
level: level,
text: text,
line: this.getLineNumber(content, match.index)
});
}
// Find custom HTML anchors
const anchorRegex = /<a[^>]+id=["']([^"']+)["'][^>]*>/g;
while ((match = anchorRegex.exec(content)) !== null) {
const id = match[1];
this.anchorMap.set(id, {
type: 'html_anchor',
line: this.getLineNumber(content, match.index)
});
}
// Find element IDs
const idRegex = /<[^>]+id=["']([^"']+)["'][^>]*>/g;
while ((match = idRegex.exec(content)) !== null) {
const id = match[1];
if (!this.anchorMap.has(id)) {
this.anchorMap.set(id, {
type: 'element_id',
line: this.getLineNumber(content, match.index)
});
}
}
}
extractLinks(content) {
const links = [];
// Markdown links: [text](url)
const markdownLinkRegex = /\[([^\]]*)\]\(([^)]+)\)/g;
let match;
while ((match = markdownLinkRegex.exec(content)) !== null) {
const text = match[1];
const url = match[2].trim();
const line = this.getLineNumber(content, match.index);
links.push({
type: 'markdown',
text: text,
url: url,
line: line,
raw: match[0]
});
}
// HTML links: <a href="url">text</a>
const htmlLinkRegex = /<a[^>]+href=["']([^"']+)["'][^>]*>(.*?)<\/a>/gi;
while ((match = htmlLinkRegex.exec(content)) !== null) {
const url = match[1].trim();
const text = match[2].replace(/<[^>]*>/g, '').trim();
const line = this.getLineNumber(content, match.index);
links.push({
type: 'html',
text: text,
url: url,
line: line,
raw: match[0]
});
}
return links;
}
validateLink(link, baseURL) {
this.linkReport.total++;
const url = link.url;
const isExternal = this.isExternalLink(url);
const isFragment = url.startsWith('#');
const isRelative = !isExternal && !isFragment && !url.startsWith('/');
let validationResult = {
link: link,
isValid: false,
isExternal: isExternal,
isFragment: isFragment,
isRelative: isRelative,
error: null
};
try {
if (isFragment) {
// Validate fragment identifier
validationResult = this.validateFragment(link);
} else if (isExternal && this.options.checkExternalLinks) {
// Validate external link (would require async handling)
validationResult.isValid = true; // Placeholder
this.linkReport.external++;
} else {
// Local file link validation would go here
validationResult.isValid = true; // Placeholder
}
} catch (error) {
validationResult.error = error.message;
}
if (validationResult.isValid) {
this.linkReport.valid++;
} else {
this.linkReport.broken++;
}
this.linkReport.details.push(validationResult);
}
validateFragment(link) {
const fragment = link.url.substring(1); // Remove #
const exists = this.anchorMap.has(fragment);
return {
link: link,
isValid: exists,
isFragment: true,
target: this.anchorMap.get(fragment) || null,
error: exists ? null : `Fragment identifier "${fragment}" not found`
};
}
isExternalLink(url) {
return this.options.ignorePrefixes.some(prefix => url.startsWith(prefix + ':'));
}
generateHeadingId(text) {
return text
.toLowerCase()
.trim()
.replace(/[^\w\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '');
}
getLineNumber(content, position) {
return content.substring(0, position).split('\n').length;
}
generateReport() {
const report = {
...this.linkReport,
summary: this.generateSummary(),
recommendations: this.generateRecommendations()
};
if (this.options.reportBrokenLinks && this.linkReport.broken > 0) {
report.brokenLinks = this.linkReport.details.filter(link => !link.isValid);
}
return report;
}
generateSummary() {
const { total, valid, broken, external } = this.linkReport;
return {
totalLinks: total,
validLinks: valid,
brokenLinks: broken,
externalLinks: external,
validationRate: total > 0 ? (valid / total * 100).toFixed(1) + '%' : '0%',
status: broken === 0 ? 'PASS' : 'FAIL'
};
}
generateRecommendations() {
const recommendations = [];
if (this.linkReport.broken > 0) {
recommendations.push({
type: 'error',
message: `Found ${this.linkReport.broken} broken links that need to be fixed`
});
}
const duplicateAnchors = this.findDuplicateAnchors();
if (duplicateAnchors.length > 0) {
recommendations.push({
type: 'warning',
message: `Found duplicate anchor IDs: ${duplicateAnchors.join(', ')}`
});
}
const orphanAnchors = this.findOrphanAnchors();
if (orphanAnchors.length > 0) {
recommendations.push({
type: 'info',
message: `Found ${orphanAnchors.length} anchors that are not linked to`
});
}
return recommendations;
}
findDuplicateAnchors() {
const anchorCounts = new Map();
const duplicates = [];
this.anchorMap.forEach((data, id) => {
anchorCounts.set(id, (anchorCounts.get(id) || 0) + 1);
});
anchorCounts.forEach((count, id) => {
if (count > 1) {
duplicates.push(id);
}
});
return duplicates;
}
findOrphanAnchors() {
const linkedAnchors = new Set();
const orphans = [];
// Collect all referenced fragments
this.linkReport.details.forEach(detail => {
if (detail.isFragment && detail.link.url.startsWith('#')) {
linkedAnchors.add(detail.link.url.substring(1));
}
});
// Find anchors that aren't referenced
this.anchorMap.forEach((data, id) => {
if (!linkedAnchors.has(id)) {
orphans.push(id);
}
});
return orphans;
}
exportReport(format = 'json') {
const report = this.generateReport();
switch (format) {
case 'json':
return JSON.stringify(report, null, 2);
case 'markdown':
return this.generateMarkdownReport(report);
case 'csv':
return this.generateCSVReport(report);
default:
return report;
}
}
generateMarkdownReport(report) {
let markdown = `# Link Validation Report
## Summary
- **Total Links**: ${report.summary.totalLinks}
- **Valid Links**: ${report.summary.validLinks}
- **Broken Links**: ${report.summary.brokenLinks}
- **External Links**: ${report.summary.externalLinks}
- **Validation Rate**: ${report.summary.validationRate}
- **Status**: ${report.summary.status}
`;
if (report.brokenLinks && report.brokenLinks.length > 0) {
markdown += `## Broken Links
| Line | Type | Text | URL | Error |
|------|------|------|-----|-------|
`;
report.brokenLinks.forEach(link => {
markdown += `| ${link.link.line} | ${link.link.type} | ${link.link.text} | ${link.link.url} | ${link.error || 'N/A'} |
`;
});
}
if (report.recommendations.length > 0) {
markdown += `
## Recommendations
`;
report.recommendations.forEach(rec => {
const icon = rec.type === 'error' ? '❌' : rec.type === 'warning' ? '⚠️' : 'ℹ️';
markdown += `${icon} **${rec.type.toUpperCase()}**: ${rec.message}
`;
});
}
return markdown;
}
}
// Usage example
const validator = new AnchorLinkValidator({
validateFragments: true,
reportBrokenLinks: true
});
// Validate a Markdown document
const markdownContent = `
# Main Title
## Section 1 {#section-1}
Content with [link to section 2](#section-2).
## Section 2
Content with [broken link](#nonexistent).
`;
const validationReport = validator.validateDocument(markdownContent);
console.log(validationReport.summary);
Integration with Modern Documentation Systems
Anchor link optimization integrates seamlessly with comprehensive documentation platforms. When combined with automation workflows and content validation, anchor link systems enable systematic link checking, automatic table of contents generation, and consistent navigation patterns across large documentation projects.
For enhanced content organization, anchor link systems work effectively with advanced table systems and data presentation to create comprehensive navigation within complex data tables, enabling users to link directly to specific data sections and maintain context while exploring large datasets.
When developing extensive documentation architectures, anchor link systems complement Progressive Web App documentation platforms by providing offline navigation capabilities, cached anchor link resolution, and enhanced user experience for technical documentation that functions effectively without network connectivity.
Conclusion
Markdown anchor links and fragment identifiers transform static documentation into navigable, interconnected content systems that enhance user experience, improve accessibility, and enable sophisticated cross-referencing capabilities. By implementing automatic heading ID generation, comprehensive table of contents systems, and robust link validation processes, technical teams can create documentation that serves both human readers and automated systems effectively.
The key to successful anchor link implementation lies in establishing consistent ID generation patterns, implementing comprehensive navigation enhancements, and maintaining link integrity through systematic validation processes. Whether you’re creating technical documentation, educational content, or complex reference materials, the anchor link techniques covered in this guide provide the foundation for building navigable, accessible content that scales with your documentation needs.
Remember to test anchor link functionality across different platforms and devices, implement accessibility best practices for navigation elements, and establish clear conventions for link naming and organization within your team. With proper implementation of anchor link systems, your Markdown documentation can achieve new levels of usability and professional navigation that enhances content discovery and user engagement.