Markdown custom directives and extensions enable advanced content management by extending standard Markdown syntax with specialized features, interactive components, and domain-specific functionality. While basic Markdown provides excellent foundational formatting capabilities, custom directives allow technical teams to create sophisticated content systems with reusable components, conditional rendering, and dynamic content generation tailored to specific organizational needs and workflow requirements.

Why Master Markdown Custom Directives?

Professional custom directive implementation provides essential benefits for advanced content systems:

  • Enhanced Functionality: Extend Markdown beyond basic formatting with interactive components and specialized features
  • Content Reusability: Create reusable content blocks and templates that maintain consistency across large documentation systems
  • Domain-Specific Language: Develop custom syntax that matches your organization’s specific content management requirements
  • Integration Flexibility: Seamlessly integrate with existing content management systems and development workflows
  • Performance Optimization: Implement efficient content processing and rendering strategies for complex interactive features

Foundation Custom Directive Concepts

Understanding Directive Syntax Patterns

Common patterns for implementing custom Markdown directives:

<!-- Block-level directives -->
:::info
This is an information callout block with custom styling and behavior.
:::

<!-- Inline directives -->
This text contains a :badge[Important]{color=red} inline directive.

<!-- Attribute-based directives -->
{.custom-class #custom-id data-component="interactive"}
This paragraph has custom attributes applied.

<!-- Shortcode-style directives -->
{{< alert type="warning" >}}
This is a shortcode-style warning alert.
{{< /alert >}}

<!-- Fence-style directives -->
type: bar
data: [10, 20, 30, 40]
title: Sample Chart Data

### Core Directive Processing Architecture

```javascript
// directive-processor.js - Foundation for custom directive processing
const unified = require('unified');
const remarkParse = require('remark-parse');
const remarkStringify = require('remark-stringify');
const { visit } = require('unist-util-visit');

class MarkdownDirectiveProcessor {
    constructor(options = {}) {
        this.options = {
            enableCustomSyntax: options.enableCustomSyntax !== false,
            allowUnsafeDirectives: options.allowUnsafeDirectives || false,
            customDirectives: options.customDirectives || new Map(),
            preprocessors: options.preprocessors || [],
            postprocessors: options.postprocessors || [],
            ...options
        };
        
        this.processor = this.createProcessor();
        this.directiveHandlers = new Map();
        this.setupDefaultDirectives();
    }
    
    createProcessor() {
        return unified()
            .use(remarkParse)
            .use(this.createDirectivePlugin())
            .use(remarkStringify);
    }
    
    createDirectivePlugin() {
        const self = this;
        
        return function directivePlugin() {
            return function transformer(tree, file) {
                // Process preprocessors first
                for (const preprocessor of self.options.preprocessors) {
                    tree = preprocessor(tree, file) || tree;
                }
                
                // Process custom directives
                self.processDirectives(tree, file);
                
                // Process postprocessors
                for (const postprocessor of self.options.postprocessors) {
                    tree = postprocessor(tree, file) || tree;
                }
                
                return tree;
            };
        };
    }
    
    processDirectives(tree, file) {
        // Process block-level directives (container syntax)
        visit(tree, 'containerDirective', (node, index, parent) => {
            this.handleDirective(node, 'container', index, parent, file);
        });
        
        // Process leaf directives (single-line)
        visit(tree, 'leafDirective', (node, index, parent) => {
            this.handleDirective(node, 'leaf', index, parent, file);
        });
        
        // Process text directives (inline)
        visit(tree, 'textDirective', (node, index, parent) => {
            this.handleDirective(node, 'text', index, parent, file);
        });
        
        // Process custom fence blocks
        visit(tree, 'code', (node, index, parent) => {
            if (node.lang && this.directiveHandlers.has(`fence:${node.lang}`)) {
                this.handleDirective({
                    type: 'fenceDirective',
                    name: node.lang,
                    value: node.value,
                    attributes: {}
                }, 'fence', index, parent, file);
            }
        });
        
        // Process comment-based directives
        visit(tree, 'html', (node, index, parent) => {
            const commentMatch = node.value.match(/<!--\s*(\w+):\s*(.+?)\s*-->/);
            if (commentMatch) {
                this.handleDirective({
                    type: 'commentDirective',
                    name: commentMatch[1].toLowerCase(),
                    value: commentMatch[2],
                    attributes: {}
                }, 'comment', index, parent, file);
            }
        });
    }
    
    handleDirective(node, directiveType, index, parent, file) {
        const directiveName = node.name.toLowerCase();
        const handlerKey = `${directiveType}:${directiveName}`;
        
        if (this.directiveHandlers.has(handlerKey)) {
            try {
                const handler = this.directiveHandlers.get(handlerKey);
                const result = handler(node, {
                    type: directiveType,
                    index,
                    parent,
                    file,
                    processor: this
                });
                
                if (result && parent && typeof index === 'number') {
                    parent.children[index] = result;
                }
            } catch (error) {
                console.error(`Error processing directive ${directiveName}:`, error);
                
                // Create error node
                parent.children[index] = {
                    type: 'paragraph',
                    children: [{
                        type: 'text',
                        value: `[Directive Error: ${directiveName} - ${error.message}]`
                    }]
                };
            }
        }
    }
    
    registerDirective(name, type, handler) {
        const key = `${type}:${name.toLowerCase()}`;
        this.directiveHandlers.set(key, handler);
    }
    
    setupDefaultDirectives() {
        // Alert/callout directives
        this.registerDirective('info', 'container', this.createAlertHandler('info'));
        this.registerDirective('warning', 'container', this.createAlertHandler('warning'));
        this.registerDirective('error', 'container', this.createAlertHandler('error'));
        this.registerDirective('success', 'container', this.createAlertHandler('success'));
        
        // Inline formatting directives
        this.registerDirective('badge', 'text', this.createBadgeHandler());
        this.registerDirective('highlight', 'text', this.createHighlightHandler());
        
        // Content inclusion directives
        this.registerDirective('include', 'comment', this.createIncludeHandler());
        this.registerDirective('template', 'comment', this.createTemplateHandler());
        
        // Interactive component directives
        this.registerDirective('button', 'leaf', this.createButtonHandler());
        this.registerDirective('tabs', 'container', this.createTabsHandler());
        
        // Data visualization directives
        this.registerDirective('chart', 'fence', this.createChartHandler());
        this.registerDirective('diagram', 'fence', this.createDiagramHandler());
    }
    
    createAlertHandler(alertType) {
        return (node, context) => {
            const title = node.attributes?.title || null;
            const className = `alert alert-${alertType}`;
            
            return {
                type: 'paragraph',
                data: {
                    hName: 'div',
                    hProperties: {
                        className: [className],
                        'data-alert-type': alertType
                    }
                },
                children: [
                    ...(title ? [{
                        type: 'strong',
                        children: [{ type: 'text', value: title }]
                    }, { type: 'text', value: '\n' }] : []),
                    ...node.children
                ]
            };
        };
    }
    
    createBadgeHandler() {
        return (node, context) => {
            const color = node.attributes?.color || 'primary';
            const size = node.attributes?.size || 'normal';
            
            return {
                type: 'text',
                data: {
                    hName: 'span',
                    hProperties: {
                        className: [`badge badge-${color} badge-${size}`],
                        'data-badge': true
                    }
                },
                value: node.children[0]?.value || ''
            };
        };
    }
    
    createHighlightHandler() {
        return (node, context) => {
            const color = node.attributes?.color || 'yellow';
            
            return {
                type: 'text',
                data: {
                    hName: 'mark',
                    hProperties: {
                        className: [`highlight highlight-${color}`],
                        'data-highlight': true
                    }
                },
                value: node.children[0]?.value || ''
            };
        };
    }
    
    createIncludeHandler() {
        return (node, context) => {
            const filePath = node.value.trim();
            
            try {
                const fs = require('fs');
                const path = require('path');
                
                // Security check - only allow relative paths
                if (path.isAbsolute(filePath) || filePath.includes('..')) {
                    throw new Error('Absolute paths and parent directory access not allowed');
                }
                
                const fullPath = path.resolve(context.file.dirname || process.cwd(), filePath);
                const includedContent = fs.readFileSync(fullPath, 'utf8');
                
                // Parse included content
                const includedTree = this.processor.parse(includedContent);
                
                return {
                    type: 'root',
                    children: includedTree.children
                };
            } catch (error) {
                return {
                    type: 'paragraph',
                    children: [{
                        type: 'text',
                        value: `[Include Error: ${filePath} - ${error.message}]`
                    }]
                };
            }
        };
    }
    
    createTemplateHandler() {
        return (node, context) => {
            const templateName = node.value.trim();
            
            // Template processing would integrate with your template engine
            return {
                type: 'paragraph',
                data: {
                    hName: 'div',
                    hProperties: {
                        className: ['template-placeholder'],
                        'data-template': templateName
                    }
                },
                children: [{
                    type: 'text',
                    value: `[Template: ${templateName}]`
                }]
            };
        };
    }
    
    createButtonHandler() {
        return (node, context) => {
            const text = node.children[0]?.value || 'Button';
            const variant = node.attributes?.variant || 'primary';
            const size = node.attributes?.size || 'medium';
            const href = node.attributes?.href;
            const onclick = node.attributes?.onclick;
            
            const element = href ? 'a' : 'button';
            const properties = {
                className: [`btn btn-${variant} btn-${size}`],
                'data-button': true
            };
            
            if (href) {
                properties.href = href;
            }
            
            if (onclick && this.options.allowUnsafeDirectives) {
                properties.onclick = onclick;
            }
            
            return {
                type: 'text',
                data: {
                    hName: element,
                    hProperties: properties
                },
                value: text
            };
        };
    }
    
    createTabsHandler() {
        return (node, context) => {
            const tabs = [];
            const tabContent = [];
            
            // Process tab children
            visit(node, 'containerDirective', (tabNode) => {
                if (tabNode.name === 'tab') {
                    const title = tabNode.attributes?.title || `Tab ${tabs.length + 1}`;
                    tabs.push(title);
                    tabContent.push(tabNode.children);
                }
            });
            
            return {
                type: 'paragraph',
                data: {
                    hName: 'div',
                    hProperties: {
                        className: ['tabs-container'],
                        'data-tabs': JSON.stringify(tabs)
                    }
                },
                children: [{
                    type: 'text',
                    value: `[Interactive Tabs Component: ${tabs.join(', ')}]`
                }]
            };
        };
    }
    
    createChartHandler() {
        return (node, context) => {
            try {
                const config = this.parseChartConfig(node.value);
                
                return {
                    type: 'paragraph',
                    data: {
                        hName: 'div',
                        hProperties: {
                            className: ['chart-container'],
                            'data-chart-config': JSON.stringify(config)
                        }
                    },
                    children: [{
                        type: 'text',
                        value: `[Chart: ${config.type || 'unknown'}]`
                    }]
                };
            } catch (error) {
                return {
                    type: 'paragraph',
                    children: [{
                        type: 'text',
                        value: `[Chart Error: ${error.message}]`
                    }]
                };
            }
        };
    }
    
    createDiagramHandler() {
        return (node, context) => {
            const diagramType = node.attributes?.type || 'flowchart';
            
            return {
                type: 'paragraph',
                data: {
                    hName: 'div',
                    hProperties: {
                        className: ['diagram-container'],
                        'data-diagram-type': diagramType,
                        'data-diagram-content': node.value
                    }
                },
                children: [{
                    type: 'text',
                    value: `[Diagram: ${diagramType}]`
                }]
            };
        };
    }
    
    parseChartConfig(configString) {
        const config = {};
        const lines = configString.trim().split('\n');
        
        for (const line of lines) {
            const [key, ...valueParts] = line.split(':');
            if (key && valueParts.length > 0) {
                const value = valueParts.join(':').trim();
                
                // Try to parse as JSON for arrays/objects
                try {
                    config[key.trim()] = JSON.parse(value);
                } catch {
                    config[key.trim()] = value;
                }
            }
        }
        
        return config;
    }
    
    async process(markdown, file = {}) {
        try {
            const result = await this.processor.process({
                value: markdown,
                path: file.path,
                dirname: file.dirname
            });
            
            return result.toString();
        } catch (error) {
            console.error('Markdown processing error:', error);
            throw error;
        }
    }
    
    addPreprocessor(preprocessor) {
        this.options.preprocessors.push(preprocessor);
    }
    
    addPostprocessor(postprocessor) {
        this.options.postprocessors.push(postprocessor);
    }
    
    getRegisteredDirectives() {
        return Array.from(this.directiveHandlers.keys()).map(key => {
            const [type, name] = key.split(':');
            return { type, name };
        });
    }
}

module.exports = MarkdownDirectiveProcessor;

Advanced Directive Implementation Patterns

Interactive Component Directives

// interactive-directives.js - Advanced interactive component system
class InteractiveDirectiveSystem {
    constructor(processor) {
        this.processor = processor;
        this.componentRegistry = new Map();
        this.setupInteractiveDirectives();
    }
    
    setupInteractiveDirectives() {
        // Collapsible content directive
        this.processor.registerDirective('details', 'container', (node, context) => {
            const summary = node.attributes?.summary || 'Details';
            const open = node.attributes?.open === 'true';
            
            return {
                type: 'paragraph',
                data: {
                    hName: 'details',
                    hProperties: {
                        className: ['collapsible-content'],
                        open: open || undefined
                    }
                },
                children: [
                    {
                        type: 'text',
                        data: {
                            hName: 'summary',
                            hProperties: { className: ['collapsible-summary'] }
                        },
                        value: summary
                    },
                    ...node.children
                ]
            };
        });
        
        // Code playground directive
        this.processor.registerDirective('playground', 'fence', (node, context) => {
            const language = node.name;
            const code = node.value;
            const editable = node.attributes?.editable !== 'false';
            const runnable = node.attributes?.runnable === 'true';
            
            const playgroundConfig = {
                language,
                code,
                editable,
                runnable,
                theme: node.attributes?.theme || 'light'
            };
            
            return {
                type: 'paragraph',
                data: {
                    hName: 'div',
                    hProperties: {
                        className: ['code-playground'],
                        'data-playground-config': JSON.stringify(playgroundConfig)
                    }
                },
                children: [{
                    type: 'text',
                    value: `[Code Playground: ${language}]`
                }]
            };
        });
        
        // Form input directive
        this.processor.registerDirective('input', 'leaf', (node, context) => {
            const type = node.attributes?.type || 'text';
            const name = node.attributes?.name || 'input';
            const placeholder = node.attributes?.placeholder || '';
            const required = node.attributes?.required === 'true';
            
            return {
                type: 'text',
                data: {
                    hName: 'input',
                    hProperties: {
                        type,
                        name,
                        placeholder,
                        required: required || undefined,
                        className: ['form-input']
                    }
                },
                value: ''
            };
        });
        
        // Progress bar directive
        this.processor.registerDirective('progress', 'leaf', (node, context) => {
            const value = parseInt(node.attributes?.value || '0');
            const max = parseInt(node.attributes?.max || '100');
            const label = node.attributes?.label || `${value}%`;
            
            return {
                type: 'paragraph',
                data: {
                    hName: 'div',
                    hProperties: {
                        className: ['progress-container']
                    }
                },
                children: [
                    {
                        type: 'text',
                        data: {
                            hName: 'progress',
                            hProperties: {
                                value,
                                max,
                                className: ['progress-bar']
                            }
                        },
                        value: ''
                    },
                    {
                        type: 'text',
                        data: {
                            hName: 'span',
                            hProperties: {
                                className: ['progress-label']
                            }
                        },
                        value: label
                    }
                ]
            };
        });
        
        // Video embed directive
        this.processor.registerDirective('video', 'leaf', (node, context) => {
            const src = node.attributes?.src;
            const poster = node.attributes?.poster;
            const controls = node.attributes?.controls !== 'false';
            const autoplay = node.attributes?.autoplay === 'true';
            const muted = node.attributes?.muted === 'true';
            
            if (!src) {
                return {
                    type: 'paragraph',
                    children: [{
                        type: 'text',
                        value: '[Video Error: No source specified]'
                    }]
                };
            }
            
            const properties = {
                src,
                controls: controls || undefined,
                autoplay: autoplay || undefined,
                muted: muted || undefined,
                className: ['embedded-video']
            };
            
            if (poster) {
                properties.poster = poster;
            }
            
            return {
                type: 'text',
                data: {
                    hName: 'video',
                    hProperties: properties
                },
                value: ''
            };
        });
        
        // Card layout directive
        this.processor.registerDirective('card', 'container', (node, context) => {
            const title = node.attributes?.title;
            const image = node.attributes?.image;
            const variant = node.attributes?.variant || 'default';
            
            const cardChildren = [];
            
            if (image) {
                cardChildren.push({
                    type: 'text',
                    data: {
                        hName: 'img',
                        hProperties: {
                            src: image,
                            className: ['card-image'],
                            alt: title || 'Card image'
                        }
                    },
                    value: ''
                });
            }
            
            if (title) {
                cardChildren.push({
                    type: 'text',
                    data: {
                        hName: 'h3',
                        hProperties: {
                            className: ['card-title']
                        }
                    },
                    value: title
                });
            }
            
            cardChildren.push({
                type: 'paragraph',
                data: {
                    hName: 'div',
                    hProperties: {
                        className: ['card-content']
                    }
                },
                children: node.children
            });
            
            return {
                type: 'paragraph',
                data: {
                    hName: 'div',
                    hProperties: {
                        className: [`card card-${variant}`]
                    }
                },
                children: cardChildren
            };
        });
    }
    
    // Register custom component renderer
    registerComponent(name, renderer) {
        this.componentRegistry.set(name, renderer);
        
        this.processor.registerDirective(name, 'container', (node, context) => {
            try {
                return renderer(node, context);
            } catch (error) {
                return {
                    type: 'paragraph',
                    children: [{
                        type: 'text',
                        value: `[Component Error: ${name} - ${error.message}]`
                    }]
                };
            }
        });
    }
    
    // Validate component configuration
    validateComponent(name, config) {
        const component = this.componentRegistry.get(name);
        if (!component) {
            throw new Error(`Component ${name} not registered`);
        }
        
        if (component.validate) {
            return component.validate(config);
        }
        
        return true;
    }
}

// Example usage with custom components
const processor = new MarkdownDirectiveProcessor();
const interactiveSystem = new InteractiveDirectiveSystem(processor);

// Register custom gallery component
interactiveSystem.registerComponent('gallery', (node, context) => {
    const images = [];
    
    // Extract image information from children
    visit(node, 'image', (imageNode) => {
        images.push({
            src: imageNode.url,
            alt: imageNode.alt || '',
            title: imageNode.title || ''
        });
    });
    
    return {
        type: 'paragraph',
        data: {
            hName: 'div',
            hProperties: {
                className: ['image-gallery'],
                'data-gallery-config': JSON.stringify({
                    images,
                    layout: node.attributes?.layout || 'grid',
                    columns: parseInt(node.attributes?.columns || '3')
                })
            }
        },
        children: [{
            type: 'text',
            value: `[Image Gallery: ${images.length} images]`
        }]
    };
});

module.exports = InteractiveDirectiveSystem;

Conditional Content and Dynamic Processing

// conditional-directives.js - Conditional content and dynamic processing
class ConditionalDirectiveSystem {
    constructor(processor, context = {}) {
        this.processor = processor;
        this.context = context; // User context, environment variables, etc.
        this.setupConditionalDirectives();
    }
    
    setupConditionalDirectives() {
        // Conditional content directive
        this.processor.registerDirective('if', 'container', (node, context) => {
            const condition = node.attributes?.condition;
            const negate = node.attributes?.negate === 'true';
            
            if (!condition) {
                return this.createErrorNode('if directive requires a condition attribute');
            }
            
            try {
                const result = this.evaluateCondition(condition);
                const showContent = negate ? !result : result;
                
                if (showContent) {
                    return {
                        type: 'root',
                        children: node.children
                    };
                } else {
                    return null; // Content is hidden
                }
            } catch (error) {
                return this.createErrorNode(`Condition evaluation error: ${error.message}`);
            }
        });
        
        // Environment-based content directive
        this.processor.registerDirective('env', 'container', (node, context) => {
            const env = node.attributes?.env;
            const currentEnv = this.context.environment || 'production';
            
            if (!env) {
                return this.createErrorNode('env directive requires an env attribute');
            }
            
            const envList = env.split(',').map(e => e.trim());
            
            if (envList.includes(currentEnv)) {
                return {
                    type: 'root',
                    children: node.children
                };
            }
            
            return null; // Content hidden for this environment
        });
        
        // User role-based content directive
        this.processor.registerDirective('role', 'container', (node, context) => {
            const requiredRoles = node.attributes?.roles?.split(',').map(r => r.trim()) || [];
            const userRoles = this.context.userRoles || [];
            
            const hasRequiredRole = requiredRoles.some(role => userRoles.includes(role));
            
            if (hasRequiredRole) {
                return {
                    type: 'root',
                    children: node.children
                };
            }
            
            return null; // Content hidden for this user
        });
        
        // Feature flag directive
        this.processor.registerDirective('feature', 'container', (node, context) => {
            const featureName = node.attributes?.name;
            const enabledFeatures = this.context.features || {};
            
            if (!featureName) {
                return this.createErrorNode('feature directive requires a name attribute');
            }
            
            if (enabledFeatures[featureName]) {
                return {
                    type: 'root',
                    children: node.children
                };
            }
            
            return null; // Feature not enabled
        });
        
        // Dynamic content replacement directive
        this.processor.registerDirective('replace', 'text', (node, context) => {
            const key = node.attributes?.key;
            const defaultValue = node.attributes?.default || '';
            
            if (!key) {
                return this.createErrorNode('replace directive requires a key attribute');
            }
            
            const value = this.getContextValue(key) || defaultValue;
            
            return {
                type: 'text',
                value: String(value)
            };
        });
        
        // Loop directive for repeating content
        this.processor.registerDirective('each', 'container', (node, context) => {
            const items = node.attributes?.items;
            const itemVar = node.attributes?.as || 'item';
            
            if (!items) {
                return this.createErrorNode('each directive requires an items attribute');
            }
            
            try {
                const itemArray = this.getContextValue(items) || [];
                if (!Array.isArray(itemArray)) {
                    throw new Error('Items must be an array');
                }
                
                const repeatedContent = [];
                
                for (let i = 0; i < itemArray.length; i++) {
                    const item = itemArray[i];
                    const itemContext = {
                        ...this.context,
                        [itemVar]: item,
                        [`${itemVar}Index`]: i,
                        [`${itemVar}First`]: i === 0,
                        [`${itemVar}Last`]: i === itemArray.length - 1
                    };
                    
                    // Process template with item context
                    const processedChildren = this.processTemplate(node.children, itemContext);
                    repeatedContent.push(...processedChildren);
                }
                
                return {
                    type: 'root',
                    children: repeatedContent
                };
            } catch (error) {
                return this.createErrorNode(`Loop processing error: ${error.message}`);
            }
        });
        
        // Switch/case directive
        this.processor.registerDirective('switch', 'container', (node, context) => {
            const value = node.attributes?.value;
            
            if (!value) {
                return this.createErrorNode('switch directive requires a value attribute');
            }
            
            const switchValue = this.getContextValue(value);
            let matchedCase = null;
            let defaultCase = null;
            
            // Find matching case or default
            visit(node, 'containerDirective', (caseNode) => {
                if (caseNode.name === 'case') {
                    const caseValue = caseNode.attributes?.value;
                    if (caseValue === String(switchValue)) {
                        matchedCase = caseNode;
                    }
                } else if (caseNode.name === 'default') {
                    defaultCase = caseNode;
                }
            });
            
            const selectedCase = matchedCase || defaultCase;
            
            if (selectedCase) {
                return {
                    type: 'root',
                    children: selectedCase.children
                };
            }
            
            return null; // No matching case
        });
    }
    
    evaluateCondition(condition) {
        // Simple condition evaluation - extend for more complex logic
        const operators = {
            '==': (a, b) => a == b,
            '===': (a, b) => a === b,
            '!=': (a, b) => a != b,
            '!==': (a, b) => a !== b,
            '>': (a, b) => a > b,
            '>=': (a, b) => a >= b,
            '<': (a, b) => a < b,
            '<=': (a, b) => a <= b,
            'includes': (a, b) => String(a).includes(String(b)),
            'startswith': (a, b) => String(a).startsWith(String(b)),
            'endswith': (a, b) => String(a).endsWith(String(b))
        };
        
        // Parse condition: "context.key operator value"
        const conditionRegex = /^(\w+(?:\.\w+)*)\s*(==|===|!=|!==|>=|<=|>|<|includes|startswith|endswith)\s*(.+)$/;
        const match = condition.match(conditionRegex);
        
        if (!match) {
            // Simple boolean check
            return Boolean(this.getContextValue(condition));
        }
        
        const [, keyPath, operator, value] = match;
        const contextValue = this.getContextValue(keyPath);
        const comparisonValue = this.parseValue(value);
        
        const operatorFn = operators[operator];
        if (!operatorFn) {
            throw new Error(`Unknown operator: ${operator}`);
        }
        
        return operatorFn(contextValue, comparisonValue);
    }
    
    getContextValue(keyPath) {
        const keys = keyPath.split('.');
        let value = this.context;
        
        for (const key of keys) {
            if (value && typeof value === 'object' && key in value) {
                value = value[key];
            } else {
                return undefined;
            }
        }
        
        return value;
    }
    
    parseValue(value) {
        // Try to parse as JSON first
        try {
            return JSON.parse(value);
        } catch {
            // Return as string if not valid JSON
            return value.replace(/^["']|["']$/g, ''); // Remove quotes
        }
    }
    
    processTemplate(children, itemContext) {
        // Process template variables in text nodes
        const processed = [];
        
        for (const child of children) {
            if (child.type === 'text') {
                processed.push({
                    ...child,
                    value: this.replaceVariables(child.value, itemContext)
                });
            } else {
                processed.push({
                    ...child,
                    children: child.children ? this.processTemplate(child.children, itemContext) : []
                });
            }
        }
        
        return processed;
    }
    
    replaceVariables(text, context) {
        return text.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (match, keyPath) => {
            const value = this.getContextValueFromObject(keyPath, context);
            return value !== undefined ? String(value) : match;
        });
    }
    
    getContextValueFromObject(keyPath, context) {
        const keys = keyPath.split('.');
        let value = context;
        
        for (const key of keys) {
            if (value && typeof value === 'object' && key in value) {
                value = value[key];
            } else {
                return undefined;
            }
        }
        
        return value;
    }
    
    createErrorNode(message) {
        return {
            type: 'paragraph',
            children: [{
                type: 'text',
                value: `[Directive Error: ${message}]`
            }]
        };
    }
    
    updateContext(newContext) {
        this.context = { ...this.context, ...newContext };
    }
}

module.exports = ConditionalDirectiveSystem;

Security and Performance Considerations

Secure Directive Processing

// secure-directives.js - Security-focused directive processing
const DOMPurify = require('isomorphic-dompurify');
const { JSDOM } = require('jsdom');

class SecureDirectiveProcessor {
    constructor(processor, options = {}) {
        this.processor = processor;
        this.options = {
            allowedDirectives: options.allowedDirectives || [],
            blockedDirectives: options.blockedDirectives || [],
            maxProcessingTime: options.maxProcessingTime || 5000, // 5 seconds
            maxContentLength: options.maxContentLength || 1024 * 1024, // 1MB
            sanitizeOutput: options.sanitizeOutput !== false,
            allowUnsafeEval: options.allowUnsafeEval || false,
            ...options
        };
        
        this.setupSecurityMeasures();
    }
    
    setupSecurityMeasures() {
        // Override processor methods with security checks
        const originalRegisterDirective = this.processor.registerDirective.bind(this.processor);
        
        this.processor.registerDirective = (name, type, handler) => {
            if (!this.isDirectiveAllowed(name)) {
                console.warn(`Directive ${name} is not allowed`);
                return;
            }
            
            if (this.isDirectiveBlocked(name)) {
                console.warn(`Directive ${name} is explicitly blocked`);
                return;
            }
            
            const secureHandler = this.wrapHandlerWithSecurity(handler, name);
            originalRegisterDirective(name, type, secureHandler);
        };
        
        // Override process method with additional security
        const originalProcess = this.processor.process.bind(this.processor);
        
        this.processor.process = async (markdown, file) => {
            // Content length check
            if (markdown.length > this.options.maxContentLength) {
                throw new Error(`Content too large: ${markdown.length} bytes exceeds limit of ${this.options.maxContentLength} bytes`);
            }
            
            // Processing timeout
            const processPromise = originalProcess(markdown, file);
            const timeoutPromise = new Promise((_, reject) => {
                setTimeout(() => reject(new Error('Processing timeout')), this.options.maxProcessingTime);
            });
            
            const result = await Promise.race([processPromise, timeoutPromise]);
            
            if (this.options.sanitizeOutput) {
                return this.sanitizeHtml(result);
            }
            
            return result;
        };
    }
    
    isDirectiveAllowed(name) {
        if (this.options.allowedDirectives.length === 0) {
            return true; // Allow all if no restrictions
        }
        
        return this.options.allowedDirectives.includes(name);
    }
    
    isDirectiveBlocked(name) {
        return this.options.blockedDirectives.includes(name);
    }
    
    wrapHandlerWithSecurity(handler, directiveName) {
        return (node, context) => {
            try {
                // Validate node structure
                this.validateNode(node, directiveName);
                
                // Execute handler with timeout
                const startTime = Date.now();
                const result = handler(node, context);
                const endTime = Date.now();
                
                if (endTime - startTime > 1000) { // 1 second warning
                    console.warn(`Directive ${directiveName} took ${endTime - startTime}ms to process`);
                }
                
                // Validate result
                if (result) {
                    this.validateDirectiveOutput(result, directiveName);
                }
                
                return result;
            } catch (error) {
                console.error(`Security error in directive ${directiveName}:`, error);
                
                return {
                    type: 'paragraph',
                    children: [{
                        type: 'text',
                        value: `[Security Error: ${directiveName}]`
                    }]
                };
            }
        };
    }
    
    validateNode(node, directiveName) {
        // Check for suspicious attributes
        if (node.attributes) {
            for (const [key, value] of Object.entries(node.attributes)) {
                // Block script-related attributes
                if (['onclick', 'onload', 'onerror', 'onmouseover'].includes(key.toLowerCase())) {
                    if (!this.options.allowUnsafeEval) {
                        throw new Error(`Unsafe attribute ${key} not allowed in directive ${directiveName}`);
                    }
                }
                
                // Check for suspicious values
                if (typeof value === 'string' && this.containsSuspiciousContent(value)) {
                    console.warn(`Potentially unsafe content in attribute ${key} of directive ${directiveName}`);
                }
            }
        }
        
        // Validate children content
        if (node.children) {
            this.validateChildren(node.children, directiveName);
        }
    }
    
    validateChildren(children, directiveName) {
        const visit = require('unist-util-visit');
        
        visit({ type: 'root', children }, (child) => {
            if (child.type === 'html') {
                if (!this.isHtmlSafe(child.value)) {
                    throw new Error(`Unsafe HTML detected in directive ${directiveName}`);
                }
            }
            
            if (child.value && this.containsSuspiciousContent(child.value)) {
                console.warn(`Potentially suspicious content in directive ${directiveName}`);
            }
        });
    }
    
    containsSuspiciousContent(content) {
        const suspiciousPatterns = [
            /<script[^>]*>/i,
            /javascript:/i,
            /data:text\/html/i,
            /vbscript:/i,
            /on\w+\s*=/i,
            /eval\s*\(/i,
            /Function\s*\(/i
        ];
        
        return suspiciousPatterns.some(pattern => pattern.test(content));
    }
    
    isHtmlSafe(html) {
        // Basic HTML safety check
        const dangerousTags = ['script', 'iframe', 'object', 'embed', 'form'];
        const tagPattern = /<(\w+)[^>]*>/gi;
        let match;
        
        while ((match = tagPattern.exec(html)) !== null) {
            if (dangerousTags.includes(match[1].toLowerCase())) {
                return false;
            }
        }
        
        return true;
    }
    
    validateDirectiveOutput(output, directiveName) {
        if (!output || typeof output !== 'object') {
            return;
        }
        
        // Check for suspicious data properties
        if (output.data && output.data.hProperties) {
            const props = output.data.hProperties;
            
            for (const [key, value] of Object.entries(props)) {
                if (key.startsWith('on') && !this.options.allowUnsafeEval) {
                    delete props[key];
                    console.warn(`Removed unsafe property ${key} from directive ${directiveName} output`);
                }
            }
        }
        
        // Recursively validate children
        if (output.children) {
            this.validateChildren(output.children, directiveName);
        }
    }
    
    sanitizeHtml(html) {
        if (typeof html !== 'string') {
            return html;
        }
        
        try {
            const window = new JSDOM('').window;
            const purify = DOMPurify(window);
            
            const config = {
                ALLOWED_TAGS: [
                    'p', 'div', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
                    'ul', 'ol', 'li', 'a', 'img', 'code', 'pre', 'blockquote',
                    'table', 'thead', 'tbody', 'tr', 'th', 'td', 'br', 'hr',
                    'strong', 'em', 'u', 's', 'mark', 'details', 'summary'
                ],
                ALLOWED_ATTR: [
                    'href', 'src', 'alt', 'title', 'class', 'id', 'data-*',
                    'target', 'rel', 'width', 'height'
                ],
                ALLOW_DATA_ATTR: true
            };
            
            return purify.sanitize(html, config);
        } catch (error) {
            console.error('HTML sanitization error:', error);
            return html; // Return original on error
        }
    }
    
    // Rate limiting for directive processing
    createRateLimiter(maxRequests = 100, windowMs = 60000) {
        const requests = new Map();
        
        return (directiveName) => {
            const now = Date.now();
            const key = directiveName;
            
            if (!requests.has(key)) {
                requests.set(key, []);
            }
            
            const directiveRequests = requests.get(key);
            
            // Clean old requests
            const validRequests = directiveRequests.filter(time => now - time < windowMs);
            
            if (validRequests.length >= maxRequests) {
                throw new Error(`Rate limit exceeded for directive ${directiveName}`);
            }
            
            validRequests.push(now);
            requests.set(key, validRequests);
        };
    }
}

module.exports = SecureDirectiveProcessor;

Integration with Modern Development Workflows

Markdown custom directives integrate seamlessly with comprehensive content management systems. When combined with automated content validation and quality assurance systems, custom directives enable sophisticated content processing pipelines that maintain quality and consistency while providing advanced interactive features for complex documentation and content platforms.

For advanced content presentation, custom directives work effectively with responsive design and mobile optimization techniques to create adaptive content experiences that render consistently across devices while leveraging device-specific capabilities through conditional directive processing.

When building comprehensive documentation platforms, custom directives complement search optimization and indexing systems to create searchable, interactive content that maintains SEO performance while providing rich user interactions and dynamic content generation capabilities.

Real-World Implementation Examples

Documentation Platform Integration

// docs-platform-integration.js - Complete documentation platform with custom directives
class DocumentationPlatform {
    constructor(options = {}) {
        this.options = {
            baseUrl: options.baseUrl || '',
            apiEndpoint: options.apiEndpoint || '/api',
            enableInteractive: options.enableInteractive !== false,
            userContext: options.userContext || {},
            ...options
        };
        
        this.processor = new MarkdownDirectiveProcessor({
            allowUnsafeDirectives: false,
            customDirectives: new Map()
        });
        
        this.setupDocumentationDirectives();
    }
    
    setupDocumentationDirectives() {
        // API documentation directive
        this.processor.registerDirective('api', 'container', (node, context) => {
            const method = node.attributes?.method?.toUpperCase() || 'GET';
            const endpoint = node.attributes?.endpoint || '';
            const title = node.attributes?.title || `${method} ${endpoint}`;
            
            return {
                type: 'paragraph',
                data: {
                    hName: 'div',
                    hProperties: {
                        className: ['api-documentation'],
                        'data-api-method': method,
                        'data-api-endpoint': endpoint
                    }
                },
                children: [
                    {
                        type: 'text',
                        data: {
                            hName: 'h4',
                            hProperties: { className: ['api-title'] }
                        },
                        value: title
                    },
                    {
                        type: 'paragraph',
                        data: {
                            hName: 'div',
                            hProperties: { className: ['api-method-badge', `method-${method.toLowerCase()}`] }
                        },
                        children: [{ type: 'text', value: method }]
                    },
                    {
                        type: 'paragraph',
                        data: {
                            hName: 'code',
                            hProperties: { className: ['api-endpoint'] }
                        },
                        children: [{ type: 'text', value: endpoint }]
                    },
                    ...node.children
                ]
            };
        });
        
        // Interactive code example directive
        this.processor.registerDirective('example', 'fence', (node, context) => {
            const language = node.name || 'javascript';
            const runnable = node.attributes?.runnable === 'true';
            const editable = node.attributes?.editable === 'true';
            const showOutput = node.attributes?.output === 'true';
            
            const exampleConfig = {
                language,
                code: node.value,
                runnable,
                editable,
                showOutput,
                id: `example-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
            };
            
            return {
                type: 'paragraph',
                data: {
                    hName: 'div',
                    hProperties: {
                        className: ['interactive-example'],
                        'data-example-config': JSON.stringify(exampleConfig)
                    }
                },
                children: [{
                    type: 'text',
                    value: `[Interactive Example: ${language}]`
                }]
            };
        });
        
        // Tabbed content directive
        this.processor.registerDirective('tabs', 'container', (node, context) => {
            const tabs = [];
            let currentTab = null;
            
            for (const child of node.children) {
                if (child.type === 'containerDirective' && child.name === 'tab') {
                    if (currentTab) {
                        tabs.push(currentTab);
                    }
                    
                    currentTab = {
                        title: child.attributes?.title || `Tab ${tabs.length + 1}`,
                        id: child.attributes?.id || `tab-${tabs.length}`,
                        content: child.children
                    };
                } else if (currentTab) {
                    currentTab.content.push(child);
                }
            }
            
            if (currentTab) {
                tabs.push(currentTab);
            }
            
            return {
                type: 'paragraph',
                data: {
                    hName: 'div',
                    hProperties: {
                        className: ['tabbed-content'],
                        'data-tabs': JSON.stringify(tabs.map(tab => ({ title: tab.title, id: tab.id })))
                    }
                },
                children: tabs.map(tab => ({
                    type: 'paragraph',
                    data: {
                        hName: 'div',
                        hProperties: {
                            className: ['tab-panel'],
                            'data-tab-id': tab.id
                        }
                    },
                    children: tab.content
                }))
            };
        });
        
        // Version-specific content directive
        this.processor.registerDirective('version', 'container', (node, context) => {
            const minVersion = node.attributes?.min;
            const maxVersion = node.attributes?.max;
            const currentVersion = this.options.userContext.version || '1.0.0';
            
            let showContent = true;
            
            if (minVersion && this.compareVersions(currentVersion, minVersion) < 0) {
                showContent = false;
            }
            
            if (maxVersion && this.compareVersions(currentVersion, maxVersion) > 0) {
                showContent = false;
            }
            
            if (showContent) {
                return {
                    type: 'paragraph',
                    data: {
                        hName: 'div',
                        hProperties: {
                            className: ['version-specific'],
                            'data-min-version': minVersion,
                            'data-max-version': maxVersion
                        }
                    },
                    children: node.children
                };
            }
            
            return null; // Hide content for this version
        });
        
        // Cross-reference directive
        this.processor.registerDirective('xref', 'text', (node, context) => {
            const target = node.attributes?.target;
            const type = node.attributes?.type || 'page';
            const text = node.children[0]?.value || target;
            
            if (!target) {
                return {
                    type: 'text',
                    value: '[Cross-reference error: no target]'
                };
            }
            
            const href = this.resolveReference(target, type);
            
            return {
                type: 'text',
                data: {
                    hName: 'a',
                    hProperties: {
                        href,
                        className: ['cross-reference', `xref-${type}`],
                        'data-xref-target': target
                    }
                },
                value: text
            };
        });
        
        // Glossary term directive
        this.processor.registerDirective('term', 'text', (node, context) => {
            const term = node.children[0]?.value || '';
            const definition = node.attributes?.definition;
            
            return {
                type: 'text',
                data: {
                    hName: 'abbr',
                    hProperties: {
                        className: ['glossary-term'],
                        title: definition,
                        'data-term': term
                    }
                },
                value: term
            };
        });
        
        // Changelog entry directive
        this.processor.registerDirective('changelog', 'container', (node, context) => {
            const version = node.attributes?.version;
            const date = node.attributes?.date;
            const type = node.attributes?.type || 'general'; // general, breaking, feature, fix
            
            return {
                type: 'paragraph',
                data: {
                    hName: 'div',
                    hProperties: {
                        className: ['changelog-entry', `changelog-${type}`],
                        'data-version': version,
                        'data-date': date
                    }
                },
                children: [
                    {
                        type: 'text',
                        data: {
                            hName: 'h5',
                            hProperties: { className: ['changelog-header'] }
                        },
                        value: `${version} - ${date}`
                    },
                    {
                        type: 'paragraph',
                        data: {
                            hName: 'div',
                            hProperties: { className: ['changelog-content'] }
                        },
                        children: node.children
                    }
                ]
            };
        });
    }
    
    compareVersions(version1, version2) {
        const v1Parts = version1.split('.').map(Number);
        const v2Parts = version2.split('.').map(Number);
        const maxLength = Math.max(v1Parts.length, v2Parts.length);
        
        for (let i = 0; i < maxLength; i++) {
            const v1Part = v1Parts[i] || 0;
            const v2Part = v2Parts[i] || 0;
            
            if (v1Part < v2Part) return -1;
            if (v1Part > v2Part) return 1;
        }
        
        return 0;
    }
    
    resolveReference(target, type) {
        switch (type) {
            case 'page':
                return `${this.options.baseUrl}/${target}`;
            case 'api':
                return `${this.options.baseUrl}/api/${target}`;
            case 'guide':
                return `${this.options.baseUrl}/guides/${target}`;
            case 'example':
                return `${this.options.baseUrl}/examples/${target}`;
            default:
                return `${this.options.baseUrl}/${target}`;
        }
    }
    
    async processDocument(markdown, context = {}) {
        const fullContext = {
            ...this.options.userContext,
            ...context
        };
        
        // Create conditional processor with user context
        const conditionalProcessor = new ConditionalDirectiveSystem(this.processor, fullContext);
        
        try {
            const result = await this.processor.process(markdown);
            return result;
        } catch (error) {
            console.error('Document processing error:', error);
            throw error;
        }
    }
    
    generateDirectiveDocumentation() {
        const directives = this.processor.getRegisteredDirectives();
        const docs = {
            overview: 'Custom directives available in this documentation platform',
            directives: []
        };
        
        for (const directive of directives) {
            docs.directives.push({
                name: directive.name,
                type: directive.type,
                description: this.getDirectiveDescription(directive.name),
                syntax: this.getDirectiveSyntax(directive.name, directive.type)
            });
        }
        
        return docs;
    }
    
    getDirectiveDescription(name) {
        const descriptions = {
            api: 'Documents API endpoints with method, path, and description',
            example: 'Creates interactive code examples with optional execution',
            tabs: 'Creates tabbed content sections',
            version: 'Shows content conditionally based on version requirements',
            xref: 'Creates cross-references to other documentation sections',
            term: 'Defines glossary terms with hover definitions',
            changelog: 'Formats changelog entries with version and date information'
        };
        
        return descriptions[name] || 'Custom directive';
    }
    
    getDirectiveSyntax(name, type) {
        const syntaxExamples = {
            api: ':::api{method="POST" endpoint="/users" title="Create User"}\nAPI description here\n:::',
            example: '```example{runnable="true" editable="true"}\nconsole.log("Hello World");\n```',
            tabs: ':::tabs\n:::tab{title="JavaScript"}\nJS content\n:::\n:::tab{title="Python"}\nPython content\n:::\n:::',
            version: ':::version{min="2.0.0" max="3.0.0"}\nContent for versions 2.x\n:::',
            xref: ':xref[API Reference]{target="api-guide" type="guide"}',
            term: ':term[API]{definition="Application Programming Interface"}',
            changelog: ':::changelog{version="1.2.0" date="2025-10-31" type="feature"}\nAdded new features\n:::'
        };
        
        return syntaxExamples[name] || `${type} directive syntax`;
    }
}

module.exports = DocumentationPlatform;

Performance Optimization for Custom Directives

Caching and Memoization Strategies

// directive-performance.js - Performance optimization for directive processing
class PerformantDirectiveProcessor {
    constructor(baseProcessor, options = {}) {
        this.baseProcessor = baseProcessor;
        this.options = {
            enableCaching: options.enableCaching !== false,
            cacheSize: options.cacheSize || 1000,
            enableMemoization: options.enableMemoization !== false,
            performanceMonitoring: options.performanceMonitoring || false,
            ...options
        };
        
        // LRU cache for processed results
        this.processedCache = new Map();
        this.cacheHits = 0;
        this.cacheMisses = 0;
        
        // Memoization for directive handlers
        this.memoizedHandlers = new Map();
        
        // Performance metrics
        this.metrics = {
            totalProcessingTime: 0,
            directiveProcessingTimes: new Map(),
            cacheHitRate: 0,
            processedDocuments: 0
        };
        
        this.setupPerformanceOptimizations();
    }
    
    setupPerformanceOptimizations() {
        // Wrap processor methods with caching
        const originalProcess = this.baseProcessor.process.bind(this.baseProcessor);
        
        this.baseProcessor.process = async (markdown, context = {}) => {
            const startTime = Date.now();
            
            // Generate cache key
            const cacheKey = this.generateCacheKey(markdown, context);
            
            // Check cache first
            if (this.options.enableCaching && this.processedCache.has(cacheKey)) {
                this.cacheHits++;
                this.updateCacheHitRate();
                return this.processedCache.get(cacheKey);
            }
            
            this.cacheMisses++;
            
            // Process document
            const result = await originalProcess(markdown, context);
            
            // Cache result
            if (this.options.enableCaching) {
                this.cacheResult(cacheKey, result);
            }
            
            // Update metrics
            const endTime = Date.now();
            this.updateMetrics(endTime - startTime);
            
            return result;
        };
        
        // Wrap directive registration with memoization
        const originalRegisterDirective = this.baseProcessor.registerDirective.bind(this.baseProcessor);
        
        this.baseProcessor.registerDirective = (name, type, handler) => {
            let optimizedHandler = handler;
            
            if (this.options.enableMemoization) {
                optimizedHandler = this.memoizeHandler(handler, `${type}:${name}`);
            }
            
            if (this.options.performanceMonitoring) {
                optimizedHandler = this.wrapHandlerWithMetrics(optimizedHandler, `${type}:${name}`);
            }
            
            originalRegisterDirective(name, type, optimizedHandler);
        };
    }
    
    generateCacheKey(markdown, context) {
        const crypto = require('crypto');
        const contentHash = crypto.createHash('md5').update(markdown).digest('hex');
        const contextHash = crypto.createHash('md5').update(JSON.stringify(context)).digest('hex');
        return `${contentHash}-${contextHash}`;
    }
    
    cacheResult(key, result) {
        // Implement LRU eviction
        if (this.processedCache.size >= this.options.cacheSize) {
            const firstKey = this.processedCache.keys().next().value;
            this.processedCache.delete(firstKey);
        }
        
        this.processedCache.set(key, result);
    }
    
    memoizeHandler(handler, handlerKey) {
        const memoCache = new Map();
        
        return (node, context) => {
            const nodeKey = this.generateNodeKey(node);
            const fullKey = `${handlerKey}-${nodeKey}`;
            
            if (memoCache.has(fullKey)) {
                return memoCache.get(fullKey);
            }
            
            const result = handler(node, context);
            
            // Only cache serializable results
            if (this.isSerializable(result)) {
                memoCache.set(fullKey, result);
                
                // Limit cache size per handler
                if (memoCache.size > 100) {
                    const firstKey = memoCache.keys().next().value;
                    memoCache.delete(firstKey);
                }
            }
            
            return result;
        };
    }
    
    wrapHandlerWithMetrics(handler, handlerKey) {
        return (node, context) => {
            const startTime = Date.now();
            
            try {
                const result = handler(node, context);
                const endTime = Date.now();
                
                this.updateDirectiveMetrics(handlerKey, endTime - startTime, true);
                
                return result;
            } catch (error) {
                const endTime = Date.now();
                this.updateDirectiveMetrics(handlerKey, endTime - startTime, false);
                throw error;
            }
        };
    }
    
    generateNodeKey(node) {
        const crypto = require('crypto');
        const nodeData = {
            type: node.type,
            name: node.name,
            attributes: node.attributes,
            childrenCount: node.children ? node.children.length : 0
        };
        
        return crypto.createHash('md5').update(JSON.stringify(nodeData)).digest('hex');
    }
    
    isSerializable(obj) {
        try {
            JSON.stringify(obj);
            return true;
        } catch {
            return false;
        }
    }
    
    updateCacheHitRate() {
        const total = this.cacheHits + this.cacheMisses;
        this.metrics.cacheHitRate = total > 0 ? this.cacheHits / total : 0;
    }
    
    updateMetrics(processingTime) {
        this.metrics.totalProcessingTime += processingTime;
        this.metrics.processedDocuments++;
    }
    
    updateDirectiveMetrics(handlerKey, processingTime, success) {
        if (!this.metrics.directiveProcessingTimes.has(handlerKey)) {
            this.metrics.directiveProcessingTimes.set(handlerKey, {
                totalTime: 0,
                callCount: 0,
                successCount: 0,
                errorCount: 0
            });
        }
        
        const directiveMetrics = this.metrics.directiveProcessingTimes.get(handlerKey);
        directiveMetrics.totalTime += processingTime;
        directiveMetrics.callCount++;
        
        if (success) {
            directiveMetrics.successCount++;
        } else {
            directiveMetrics.errorCount++;
        }
    }
    
    getPerformanceMetrics() {
        const avgProcessingTime = this.metrics.processedDocuments > 0 
            ? this.metrics.totalProcessingTime / this.metrics.processedDocuments 
            : 0;
        
        const directiveStats = {};
        for (const [key, stats] of this.metrics.directiveProcessingTimes) {
            directiveStats[key] = {
                averageTime: stats.callCount > 0 ? stats.totalTime / stats.callCount : 0,
                totalCalls: stats.callCount,
                successRate: stats.callCount > 0 ? stats.successCount / stats.callCount : 0
            };
        }
        
        return {
            cacheHitRate: this.metrics.cacheHitRate,
            averageProcessingTime: avgProcessingTime,
            processedDocuments: this.metrics.processedDocuments,
            cacheSize: this.processedCache.size,
            directivePerformance: directiveStats
        };
    }
    
    clearCache() {
        this.processedCache.clear();
        this.memoizedHandlers.clear();
        this.cacheHits = 0;
        this.cacheMisses = 0;
    }
    
    warmupCache(documents) {
        return Promise.all(
            documents.map(doc => this.baseProcessor.process(doc.content, doc.context))
        );
    }
}

module.exports = PerformantDirectiveProcessor;

Troubleshooting Common Custom Directive Issues

Debugging and Error Handling

Problem: Directive not processing or throwing errors during compilation

Solutions:

// Enable detailed debugging for directive processing
const processor = new MarkdownDirectiveProcessor({
    debug: true,
    errorHandling: 'detailed' // 'silent', 'basic', 'detailed'
});

// Add error boundary for directive processing
processor.addPreprocessor((tree, file) => {
    console.log('Processing tree:', JSON.stringify(tree, null, 2));
    return tree;
});

// Validate directive syntax before processing
const validateDirectiveSyntax = (content) => {
    const directivePatterns = {
        container: /:::(\w+)(?:\{([^}]*)\})?\s*\n([\s\S]*?)\n:::/g,
        leaf: /::(\w+)(?:\{([^}]*)\})?(?:\[([^\]]*)\])?/g,
        text: /:(\w+)(?:\{([^}]*)\})?(?:\[([^\]]*)\])?/g
    };
    
    const issues = [];
    
    for (const [type, pattern] of Object.entries(directivePatterns)) {
        let match;
        while ((match = pattern.exec(content)) !== null) {
            try {
                // Validate attributes syntax
                if (match[2]) {
                    JSON.parse(`{${match[2]}}`);
                }
            } catch (error) {
                issues.push({
                    type,
                    directive: match[1],
                    position: match.index,
                    error: `Invalid attributes syntax: ${error.message}`
                });
            }
        }
    }
    
    return issues;
};

Problem: Performance degradation with complex directive processing

Solutions:

// Implement directive processing timeouts
const createTimoutWrapper = (handler, timeout = 5000) => {
    return async (node, context) => {
        return Promise.race([
            Promise.resolve(handler(node, context)),
            new Promise((_, reject) => 
                setTimeout(() => reject(new Error('Directive processing timeout')), timeout)
            )
        ]);
    };
};

// Use streaming for large content processing
const processLargeContent = async (content, chunkSize = 10000) => {
    const chunks = [];
    for (let i = 0; i < content.length; i += chunkSize) {
        chunks.push(content.slice(i, i + chunkSize));
    }
    
    const results = [];
    for (const chunk of chunks) {
        const result = await processor.process(chunk);
        results.push(result);
    }
    
    return results.join('');
};

Problem: Security vulnerabilities in custom directive implementations

Solutions:

// Implement comprehensive input validation
const validateDirectiveInput = (node, allowedAttributes = []) => {
    if (node.attributes) {
        for (const [key, value] of Object.entries(node.attributes)) {
            // Check allowed attributes
            if (allowedAttributes.length > 0 && !allowedAttributes.includes(key)) {
                throw new Error(`Attribute '${key}' not allowed`);
            }
            
            // Validate attribute values
            if (typeof value === 'string') {
                // Check for script injection
                if (/<script|javascript:|data:text\/html/i.test(value)) {
                    throw new Error(`Potentially unsafe value in attribute '${key}'`);
                }
                
                // Limit attribute value length
                if (value.length > 1000) {
                    throw new Error(`Attribute '${key}' value too long`);
                }
            }
        }
    }
    
    return true;
};

// Sanitize directive output
const sanitizeDirectiveOutput = (output) => {
    if (output && output.data && output.data.hProperties) {
        const props = output.data.hProperties;
        
        // Remove event handlers
        Object.keys(props).forEach(key => {
            if (key.startsWith('on') || key.toLowerCase().includes('script')) {
                delete props[key];
            }
        });
        
        // Validate href attributes
        if (props.href && !isValidUrl(props.href)) {
            delete props.href;
        }
    }
    
    return output;
};

Conclusion

Markdown custom directives and extensions transform static content into dynamic, interactive experiences by extending the fundamental capabilities of Markdown syntax while maintaining compatibility with standard processing workflows. By implementing sophisticated directive processing systems, security measures, and performance optimizations, technical teams can create powerful content management platforms that scale efficiently while providing rich user interactions and domain-specific functionality tailored to organizational needs.

The key to successful custom directive implementation lies in balancing functionality with security, performance with flexibility, and complexity with maintainability. Whether you’re building documentation platforms, content management systems, or specialized publishing workflows, the techniques covered in this guide provide the foundation for creating robust directive systems that enhance content capabilities while preserving the simplicity and portability that makes Markdown such a valuable content creation tool.

Remember to implement comprehensive security validation for user-provided content, optimize performance for large-scale processing, and maintain clear documentation for custom directive syntax and capabilities. With proper implementation of custom directives, your Markdown-based systems can deliver sophisticated content experiences that bridge the gap between simple text formatting and full-featured content management platforms.