legal-markdown-js
Version:
Node.js implementation of LegalMarkdown for processing legal documents with markdown and YAML - Complete feature parity with Ruby version
232 lines • 9.86 kB
TypeScript
/**
* Legal Markdown Processor with Remark Pipeline (Phase 3: AST Processing)
*
* This module provides a comprehensive processor for Legal Markdown documents
* using the remark ecosystem. It combines multiple remark plugins to provide
* AST-based processing that avoids text contamination issues.
*
* Processing Flow:
* - Phase 1: Context building (YAML parsing, metadata merging) - done in context-builder.ts
* - Phase 2: String transformations (field normalization, clauses, loops) - done in string-transformations.ts
* - Phase 3: AST processing (THIS MODULE - remark plugins)
* - Phase 4: Format generation (HTML, PDF) - done in format-generator.ts
*
* Features:
* - Complete remark pipeline with all Legal Markdown plugins
* - Field tracking integration with automatic clearing
* - Cross-reference processing with section numbering
* - Metadata extraction and processing
* - Comprehensive error handling and debugging
* - Compatible with existing Legal Markdown API
*
* @example
* ```typescript
* import { processLegalMarkdownWithRemark } from './legal-markdown-processor.js';
*
* const result = await processLegalMarkdownWithRemark(content, {
* basePath: './documents',
* enableFieldTracking: true,
* debug: true
* });
*
* console.log(result.content); // Processed markdown
* console.log(result.metadata); // Extracted metadata
* console.log(result.fieldReport); // Field tracking report
* ```
*
* @see docs/architecture/03_processing_pipeline.md
* @see docs/architecture/string-transformations.md
* @module
*/
import type { Root } from 'mdast';
import type { MarkdownString } from '../../types/content-formats.js';
import type { YamlValue } from '../../types/index.js';
/**
* Pre-process content to escape underscores inside {{}} to prevent
* markdown parser from interpreting them as italic delimiters
*
* **Problem**: Field names with underscores like `{{counterparty.legal_name}}`
* would be parsed by remark as `{{counterparty.legal*name}}` because markdown
* treats `_text_` as emphasis (converted to `*text*` during parsing).
*
* **Solution**: Escape underscores to `\_` before markdown parsing. The escaped
* underscores are later unescaped in:
* - `remarkTemplateFields` (src/plugins/remark/template-fields.ts)
* - `parseMarkdownInlineFormatting` (src/plugins/remark/legal-headers-parser.ts)
*
* @see https://github.com/petalo/legal-markdown-js/issues/139
* @see src/plugins/remark/template-fields.ts - Unescapes underscores during field extraction
* @see src/plugins/remark/legal-headers-parser.ts - Excludes template fields from emphasis parsing
*
* @param content - Raw markdown content
* @returns Content with underscores escaped for legacy syntax, unchanged for Handlebars
*
* @example
* ```typescript
* // Legacy syntax - escapes underscores
* escapeTemplateUnderscores('{{legal_name}}') // => '{{legal\_name}}'
*
* // Handlebars syntax - no escaping needed
* escapeTemplateUnderscores('{{titleCase section_name}}') // => '{{titleCase section_name}}'
* escapeTemplateUnderscores('{{#if test}}') // => '{{#if test}}' (unchanged)
* ```
*/
declare function escapeTemplateUnderscores(content: string): string;
/**
* Configuration options for the Legal Markdown processor
* @interface LegalMarkdownProcessorOptions
*/
export interface LegalMarkdownProcessorOptions {
/** Base path for resolving relative imports */
basePath?: string;
/** Enable field tracking and highlighting */
enableFieldTracking?: boolean;
/** Use AST-first field tracking pipeline */
astFieldTracking?: boolean;
/** Highlight winner branch content for conditional blocks */
logicBranchHighlighting?: boolean;
/** Enable debug logging */
debug?: boolean;
/** Validate plugin execution order and log warnings */
validatePluginOrder?: boolean;
/** Additional metadata to merge with document metadata */
additionalMetadata?: Record<string, YamlValue>;
/** Custom field patterns for field tracking */
fieldPatterns?: string[];
/** Disable specific processing steps */
disableCrossReferences?: boolean;
disableFieldTracking?: boolean;
/** Metadata export options */
exportMetadata?: boolean;
exportFormat?: 'yaml' | 'json';
exportPath?: string;
/** Processing flags (for compatibility with legacy processor) */
yamlOnly?: boolean;
noHeaders?: boolean;
noClauses?: boolean;
noReferences?: boolean;
noImports?: boolean;
noMixins?: boolean;
noReset?: boolean;
noIndent?: boolean;
throwOnYamlError?: boolean;
/** Whether to add HTML comments showing import boundaries in output */
importTracing?: boolean;
/** Whether to validate type compatibility during frontmatter merging */
validateImportTypes?: boolean;
/** Whether to log detailed frontmatter merge operations */
logImportOperations?: boolean;
/** Disable automatic frontmatter merging from imported files */
disableFrontmatterMerge?: boolean;
}
/**
* Result from Legal Markdown processing
* @interface LegalMarkdownProcessorResult
*/
export interface LegalMarkdownProcessorResult {
/** Processed markdown content (always Markdown format, never HTML) */
content: MarkdownString;
/** Extracted and processed metadata */
metadata: Record<string, YamlValue>;
/** Cached AST for Phase 3 format generation (optional) */
ast?: Root;
/** Array of exported metadata files */
exportedFiles?: string[];
/** Field tracking report (if enabled) */
fieldReport?: {
totalFields: number;
uniqueFields: number;
fields: Map<string, import('../../extensions/tracking/field-tracker.js').TrackedField>;
};
/** Processing statistics and debugging info */
stats: {
processingTime: number;
pluginsUsed: string[];
crossReferencesFound: number;
fieldsTracked: number;
};
/** Any warnings or non-fatal errors encountered */
warnings: string[];
}
/**
* Create a configured remark processor for Legal Markdown
*
* This function assembles a unified processor with all the necessary remark plugins
* for Legal Markdown processing. Plugins are added in a specific order to ensure
* proper processing dependencies:
*
* **CRITICAL PLUGIN ORDER:**
* 1. Imports - MUST be first to load all content before any transformation
* 2. Legal Headers Parser - MUST be after imports to convert headers in imported files
* 3. Mixins - Content expansion before other processing
* 4. Clauses - Conditional content
* 5. Template fields - Field processing and tracking
* 6. Cross-references - Reference resolution
* 7. Headers - Final structure processing and numbering
*
* **WARNING:** Changing this order can break functionality:
* - If Legal Headers Parser runs before Imports, headers in imported files won't be converted
* - If Cross-references runs before Headers, section numbering won't be available
* - If Mixins runs before Imports, variable expansion won't work for imported content
*
* @param metadata - Document metadata from YAML frontmatter and additional sources
* @param options - Configuration options for processing
* @returns Configured unified processor ready for content processing
* @internal
*/
declare function createLegalMarkdownProcessor(metadata: Record<string, YamlValue>, options: LegalMarkdownProcessorOptions): import("unified").Processor<Root, undefined, undefined, undefined, undefined>;
/**
* Process Legal Markdown content using remark pipeline
*
* This is the main entry point for remark-based Legal Markdown processing.
* It provides a complete AST-based processing pipeline with:
* - YAML frontmatter parsing and metadata extraction
* - Template field processing with nested helper support
* - Cross-reference resolution and section numbering
* - Field tracking for document highlighting
* - Import processing for modular documents
* - Comprehensive error handling and debugging
*
* @param content - Raw Legal Markdown content to process
* @param options - Processing options and configuration
* @returns Promise resolving to processed content, metadata, and statistics
*
* @example
* ```typescript
* const result = await processLegalMarkdownWithRemark(markdownContent, {
* enableFieldTracking: true,
* basePath: './templates',
* debug: true
* });
*
* console.log(result.content); // Processed markdown
* console.log(result.stats.fieldsTracked); // Number of tracked fields
* ```
*/
export declare function processLegalMarkdown(content: string, options?: LegalMarkdownProcessorOptions): Promise<LegalMarkdownProcessorResult>;
/**
* Create a pre-configured processor instance for reuse
*
* This factory function creates a reusable processor instance with pre-configured
* options. Useful for batch processing multiple documents with the same settings.
*
* @param options - Base configuration options for all processing operations
* @returns Object with async and sync processing methods
*
* @example
* ```typescript
* const processor = createReusableLegalMarkdownProcessor({
* enableFieldTracking: true,
* basePath: './templates'
* });
*
* const result1 = await processor.process(content1);
* const result2 = await processor.process(content2, { debug: true });
* ```
*/
export declare function createReusableLegalMarkdownProcessor(options?: LegalMarkdownProcessorOptions): {
process(content: string, additionalOptions?: Partial<LegalMarkdownProcessorOptions>): Promise<LegalMarkdownProcessorResult>;
processSync(content: string, additionalOptions?: Partial<LegalMarkdownProcessorOptions>): never;
};
export { escapeTemplateUnderscores as _escapeTemplateUnderscores, createLegalMarkdownProcessor as _createLegalMarkdownProcessor, };
//# sourceMappingURL=legal-markdown-processor.d.ts.map