UNPKG

legal-markdown-js

Version:

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

204 lines 7.4 kB
/** * @fileoverview Frontmatter Merger for Import Processing * * This module provides the core functionality for merging YAML frontmatter from * imported files using the "source always wins" strategy with flattened merging. * It enables granular merging at the property level while maintaining predictable * conflict resolution. * * Features: * - Flattened merging for granular property-level control * - "Source always wins" conflict resolution strategy * - Type conflict detection and validation * - Reserved field filtering integration * - Comprehensive merge statistics and reporting * * @example * ```typescript * import { mergeFlattened, validateMergeCompatibility } from './frontmatter-merger'; * * const current = { * title: "Main Document", * config: { server: "prod", port: 8080 } * }; * * const imported = { * config: { level: "high", server: "dev" }, // server conflict - current wins * client: "Acme Corp" // new field - added * }; * * const result = mergeFlattened(current, imported); * // { * // title: "Main Document", * // config: { server: "prod", port: 8080, level: "high" }, * // client: "Acme Corp" * // } * ``` */ /** * Options for frontmatter merging */ export interface MergeOptions { /** Whether to filter reserved fields from imported metadata */ filterReserved?: boolean; /** Whether to validate type compatibility before merging */ validateTypes?: boolean; /** Whether to log merge operations for debugging */ logOperations?: boolean; /** Custom conflict resolution strategy (future extension) */ conflictStrategy?: 'source-wins' | 'import-wins' | 'error'; /** Whether to include merge statistics in result */ includeStats?: boolean; /** Maximum execution time in milliseconds (default: 10000ms) */ timeoutMs?: number; } /** * Result of a merge operation */ export interface MergeResult { /** Merged metadata object */ metadata: Record<string, any>; /** Statistics about the merge operation */ stats?: MergeStats; } /** * Statistics about a merge operation */ export interface MergeStats { /** Total properties in current metadata */ currentProperties: number; /** Total properties in imported metadata */ importedProperties: number; /** Properties added from imported metadata */ propertiesAdded: number; /** Properties that had conflicts (current wins) */ conflictsResolved: number; /** Reserved fields filtered out */ reservedFieldsFiltered: number; /** List of fields that were added */ addedFields: string[]; /** List of fields that had conflicts */ conflictedFields: string[]; /** List of reserved fields that were filtered */ filteredFields: string[]; } /** * Error thrown when merge validation fails */ export declare class MergeValidationError extends Error { field: string; currentType: string; importedType: string; constructor(message: string, field: string, currentType: string, importedType: string); } /** * Merges imported frontmatter into current frontmatter using flattened strategy * * Uses the "source always wins" strategy where the current metadata takes precedence * over imported metadata in case of conflicts. Supports granular merging at the * property level using dot notation flattening. * * @param current - Current metadata (takes precedence) * @param imported - Imported metadata to merge * @param options - Merge configuration options * @returns Merged metadata or MergeResult with statistics * * @example * ```typescript * const current = { * document: { title: "Contract", version: "1.0" }, * client: "Main Client" * }; * * const imported = { * document: { title: "Import Doc", author: "John Doe" }, // title conflicts - current wins * metadata: { created: "@today" } // new field - added * }; * * const result = mergeFlattened(current, imported, { includeStats: true }); * // result.metadata = { * // document: { title: "Contract", version: "1.0", author: "John Doe" }, * // client: "Main Client", * // metadata: { created: "@today" } * // } * // result.stats.propertiesAdded = 2 * // result.stats.conflictsResolved = 1 * ``` */ export declare function mergeFlattened(current: Record<string, any>, imported: Record<string, any>, options?: MergeOptions): Record<string, any>; export declare function mergeFlattened(current: Record<string, any>, imported: Record<string, any>, options: MergeOptions & { includeStats: true; }): MergeResult; /** * Validates that two values are compatible for merging * * Checks if the current and imported values have compatible types. * Throws MergeValidationError if types are incompatible. * * @param current - Current value * @param imported - Imported value to merge * @param key - Property key for error reporting * @throws MergeValidationError when types are incompatible * * @example * ```typescript * // Compatible types - no error * validateMergeCompatibility("string", "another string", "title"); * validateMergeCompatibility(42, 100, "count"); * * // Incompatible types - throws error * try { * validateMergeCompatibility("string", { object: true }, "config"); * } catch (error) { * console.log(error.message); // "Type conflict for 'config': current=string, imported=object" * } * ``` */ export declare function validateMergeCompatibility(current: any, imported: any, key: string): void; /** * Performs a dry run merge to preview results * * Simulates a merge operation without actually performing it. * Useful for validation and preview purposes. * * @param current - Current metadata * @param imported - Imported metadata * @param options - Merge options * @returns Preview of merge results * * @example * ```typescript * const preview = previewMerge(current, imported, { filterReserved: true }); * console.log(`Would add ${preview.stats.propertiesAdded} properties`); * console.log(`Would resolve ${preview.stats.conflictsResolved} conflicts`); * console.log(`Would filter ${preview.stats.reservedFieldsFiltered} reserved fields`); * ``` */ export declare function previewMerge(current: Record<string, any>, imported: Record<string, any>, options?: MergeOptions): MergeResult; /** * Merges multiple imported metadata objects sequentially * * Applies the merge operation sequentially across multiple imports, * where each result becomes the new "current" for the next merge. * * @param initial - Initial metadata (usually from main document) * @param imports - Array of imported metadata objects to merge * @param options - Merge options applied to all operations * @returns Final merged metadata with cumulative statistics * * @example * ```typescript * const initial = { title: "Main Doc" }; * const imports = [ * { config: { level: "high" } }, * { config: { debug: true }, client: "Acme" }, * { metadata: { version: "1.0" } } * ]; * * const result = mergeSequentially(initial, imports, { includeStats: true }); * // result.metadata contains all merged properties * // result.stats contains cumulative statistics * ``` */ export declare function mergeSequentially(initial: Record<string, any>, imports: Record<string, any>[], options?: MergeOptions): MergeResult; //# sourceMappingURL=frontmatter-merger.d.ts.map