UNPKG

legal-markdown-js

Version:

Node.js implementation of LegalMarkdown for processing legal documents with markdown and YAML - Complete feature parity with Ruby version

184 lines 6.45 kB
/** * AST-based Mixin Processor for Legal Markdown Documents * * This module provides a completely rewritten mixin processing system that uses * Abstract Syntax Tree (AST) parsing to avoid text contamination issues present * in the original string-replacement approach. * * Key improvements: * - AST-based parsing prevents variable values from contaminating other text * - Isolated node processing ensures clean variable substitution * - Maintains full compatibility with existing field tracking and highlighting * - Supports all existing mixin types: variables, helpers, conditionals * - Detects [bracket values] in frontmatter as missing values automatically * * Architecture: * 1. Parse content into AST nodes (text, variable, helper, conditional) * 2. Process each mixin node independently with isolated context * 3. Reconstruct document with resolved values * 4. Integrate with field tracking for highlighting and validation * * @example * ```typescript * import { processMixins } from './ast-mixin-processor'; * * const content = ` * Client: {{client.name}} * Amount: {{formatCurrency(amount, "EUR")}} * {{premium ? "Premium service included" : ""}} * `; * * const metadata = { * client: { name: "Acme Corp" }, * amount: 50000, * premium: true * }; * * const result = processMixins(content, metadata); * // No text contamination - each mixin processed independently * ``` * * @module */ import { LegalMarkdownOptions } from '../types'; /** * Represents a single node in the parsed AST */ export interface MixinNode { /** Type of the node content */ type: 'text' | 'variable' | 'helper' | 'conditional'; /** Original content from the document */ content: string; /** Extracted variable/expression (without {{}} brackets) */ variable?: string; /** Position in the original document */ position: { start: number; end: number; }; /** Resolved value after processing (set during resolution phase) */ resolved?: any; /** Whether this node had processing errors */ hasError?: boolean; /** Error message if processing failed */ errorMessage?: string; } /** * Result of parsing content into AST */ export interface ParseResult { /** Array of parsed nodes in document order */ nodes: MixinNode[]; /** Whether any parsing errors occurred */ hasErrors: boolean; /** Detailed error information */ errors: Array<{ node: MixinNode; message: string; position: { start: number; end: number; }; }>; } /** * Classifies a mixin variable by its content to determine processing type * * @param variable - The variable content (without {{}} brackets) * @returns The classified type * * @example * ```typescript * classifyMixinType("client.name") // → "variable" * classifyMixinType("formatDate(@today, 'DD/MM')") // → "helper" * classifyMixinType("premium ? 'Yes' : 'No'") // → "conditional" * ``` */ export declare function classifyMixinType(variable: string): 'variable' | 'helper' | 'conditional'; /** * Parses document content into an AST of mixin nodes * * This function identifies all mixin patterns in the content and creates * a structured representation that can be processed without text contamination. * * @param content - Document content to parse * @returns Parsed AST with nodes and any errors encountered * * @example * ```typescript * const content = "Hello {{name}}, amount: {{formatCurrency(total, 'EUR')}}"; * const result = parseContentToAST(content); * * // result.nodes: * // [ * // { type: 'text', content: 'Hello ', position: { start: 0, end: 6 } }, * // { type: 'variable', content: '{{name}}', variable: 'name', position: { start: 6, end: 14 } }, * // { type: 'text', content: ', amount: ', position: { start: 14, end: 25 } }, * // { type: 'helper', content: '{{formatCurrency(total, \'EUR\')}}', variable: 'formatCurrency(total, \'EUR\')', position: { start: 25, end: 56 } } * // ] * ``` */ export declare function parseContentToAST(content: string): ParseResult; /** * Detects values in frontmatter that are wrapped in [brackets] and should be treated as missing values * * @param metadata - The frontmatter metadata object * @returns Set of field paths that contain bracket values * * @example * ```typescript * const metadata = { * client: { name: "[CLIENT NAME]" }, * amount: 50000, * description: "[PROJECT DESCRIPTION]" * }; * * const bracketFields = detectBracketValues(metadata); * // Returns: Set(["client.name", "description"]) * ``` */ export declare function detectBracketValues(metadata: Record<string, any>, prefix?: string): Set<string>; /** * Processes parsed AST nodes and resolves all mixin values * * This is the core processing function that takes parsed nodes and resolves * each mixin independently, preventing text contamination. * * @param nodes - Parsed AST nodes to process * @param metadata - Document metadata for variable resolution * @param options - Processing options * @returns Processed document content with resolved mixins */ export declare function processMixinAST(nodes: MixinNode[], metadata: Record<string, any>, options?: LegalMarkdownOptions): string; /** * Main entry point for mixin processing with AST-based approach * * This function provides complete API compatibility with the original processMixins * while using the new AST-based processing to prevent text contamination. * * @param content - The document content containing mixin references * @param metadata - Document metadata with variable values * @param options - Processing options * @returns Processed content with mixins resolved * * @example * ```typescript * // API identical to original processMixins * const content = ` * Client: {{client.name}} * Amount: {{formatCurrency(amount, "EUR")}} * {{premium ? "Premium service" : "Standard service"}} * `; * * const metadata = { * client: { name: "Acme Corp" }, * amount: 50000, * premium: true * }; * * const result = processMixins(content, metadata, { enableFieldTrackingInMarkdown: true }); * // Clean output without text contamination * ``` */ export declare function processMixins(content: string, metadata: Record<string, any>, options?: LegalMarkdownOptions): string; //# sourceMappingURL=ast-mixin-processor.d.ts.map