- Overview
- Remark Plugin Extensions
- Pipeline Extensions
- Helper & Formatter Extensions
- CLI & Tooling Hooks
- Best Practices
Legal Markdown JS exposes a small set of extension surfaces so teams can add new behaviour without forking the processor. The supported patterns centre on the remark ecosystem, pipeline helpers and helper libraries.
Custom remark plugins are the preferred way to augment document processing.
- Register plugins by extending
src/plugins/remark/plugin-metadata-registry.tswith dependency metadata and adding the implementation undersrc/plugins/remark/ - Provide
runBefore,runAfterandconflictsdeclarations so the validator (PluginOrderValidator) can maintain a valid execution order - Export configuration hooks from
src/extensions/remark/legal-markdown-processor.tsto make the plugin available to consumers
// Example metadata entry
{
name: 'remarkMyPlugin',
description: 'Custom AST transform',
runAfter: ['remarkTemplateFields'],
required: false,
}Plugins receive the shared options object and can attach results to the
processor return value via the additionalData field on
LegalMarkdownProcessorResult. Detailed guidance lives in
docs/architecture/04_remark_integration.md.
The three-phase pipeline intentionally keeps Phase 1 and Phase 3 composable:
- Wrap
buildProcessingContextto inject additional metadata or resolve organisation-specific force-commands - Compose
generateAllFormatswith custom format writers (e.g., JSON, DOCX) by augmenting the returned file list after Phase 3 completes - Add orchestration layers that call
processAndGenerateFormatswith custom scheduling, queuing or post-processing concerns
Pipeline consumers should treat the cached LegalMarkdownProcessorResult as the
single source of truth for processed content and metadata.
The PDF generation layer uses a pluggable connector architecture defined in
src/extensions/generators/pdf-connectors/:
types.ts-PdfConnectorinterface +PdfConnectorPreferenceunion ('auto' | 'puppeteer' | 'system-chrome' | 'weasyprint')puppeteer-connector.ts- uses bundled Puppeteer for hermetic, reproducible rendering (requiresnpm install puppeteer)system-chrome-connector.ts- launches any installed Chromium-family browser via--headless --print-to-pdf; zero-install for users with a browserweasyprint-connector.ts- delegates to the Pythonweasyprintexecutable; useful in server environments without a displayresolver.ts-resolvePdfConnector(preference)selects the first available connector forpreference: 'auto', or validates and returns the requested oneindex.ts- re-exportscreatePdfConnectorandresolvePdfConnector
To force a specific backend set pdf.connector in .legalmdrc or use
LEGAL_MD_PDF_CONNECTOR=weasyprint legal-md ... for temporary overrides.
Helper libraries remain pluggable through existing registries:
- Template helpers - new functions can be added in
src/core/helpers/*and exposed via the template-fields plugin configuration - Handlebars helpers - register custom helpers using the Handlebars engine (see details below)
- HTML/PDF generators - extend
HtmlGenerator/PdfGeneratorwith custom templates or post-process the generated markup/files before writing them to disk - Metadata exporters - consume
LegalMarkdownProcessorResult.metadatato publish additional reports (e.g., compliance summaries)
When adding helpers, update shared helper typing in src/types.ts and include
targeted unit tests.
Since v3.5.0, Legal Markdown supports Handlebars as the standard template engine alongside legacy custom syntax (deprecated).
Registering Custom Handlebars Helpers:
import { registerCustomHelper } from './extensions/handlebars-engine';
// Register a custom helper
registerCustomHelper('formatPhoneNumber', (phoneNumber: string) => {
return phoneNumber.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
});Usage in templates:
Available Helper Categories:
- Date helpers:
formatDate,addYears,addMonths,addDays, etc. - Number helpers:
formatCurrency,formatPercent,numberToWords, etc. - String helpers:
capitalize,titleCase,truncate,concat, etc. - Math helpers:
multiply,divide,add,subtract
See docs/helpers/README.md for complete reference.
Architecture:
- Helper registration:
src/extensions/handlebars-engine.ts - Template processing:
src/extensions/template-loops.ts - Syntax detection: Automatic (Handlebars vs Legacy)
- Migration path: See
docs/handlebars-migration.md
Best Practices:
- Use Handlebars syntax for new templates
- Register helpers in
handlebars-engine.tsinitialization - Provide TypeScript types for helper arguments
- Include unit tests for custom helpers
- Document helpers in
docs/helpers/README.md
CliServiceandInteractiveServiceaccept option overrides; wrapper scripts can inject defaults (e.g., enforce--validate-plugin-orderin specific environments)- Downstream tools can consume the
tests/fixtures and integration harness to validate custom plugins against regression suites - The browser build exposes the same public API, enabling extensions inside the web interface without diverging processing logic
- Validate plugin order - always update metadata and run
tests/integration/plugin-order-validation.integration.test.ts - Respect cached AST - avoid triggering extra remark runs; reuse the
LegalMarkdownProcessorResultprovided by Phase 2 - Document new behaviour - mirror this architecture set when introducing new extension types to keep the documentation cohesive
- Test thoroughly - add unit and integration coverage before enabling extensions in production pipelines
These guidelines ensure extensions remain compatible with the shared pipeline and retain the deterministic behaviour expected by legal workflows.