UNPKG

legal-markdown-js

Version:

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

194 lines 7.05 kB
/** * Metadata Export System for Legal Markdown Documents * * This module provides functionality for exporting document metadata to external * files in various formats. It supports YAML and JSON export formats with * configurable output paths and metadata filtering. * * Features: * - Metadata export to YAML and JSON formats * - Configurable output paths and filenames * - Metadata filtering and processing * - Internal metadata key removal * - Directory creation for output files * - Error handling and logging * - Support for custom export configurations * * @example * ```typescript * import { exportMetadata } from './metadata-exporter.js'; * * // Export metadata to YAML * const result = exportMetadata(metadata, 'yaml', './output'); * console.log('Exported files:', result.exportedFiles); * * // Export with custom configuration * const metadata = { * title: 'Legal Agreement', * 'meta-yaml-output': 'custom-metadata.yaml', * 'meta-json-output': 'custom-metadata.json' * }; * const result = exportMetadata(metadata); * ``` * * @module */ import * as fs from 'fs'; import { logger } from '../../utils/logger.js'; import * as path from 'path'; import * as yaml from 'js-yaml'; /** * Exports document metadata to external files * * Processes document metadata and exports it to specified formats (YAML/JSON) * with support for custom output paths and metadata filtering. Handles directory * creation and provides comprehensive error handling. * * @function exportMetadata * @param {Record<string, any>} metadata - Document metadata to export * @param {'yaml' | 'json'} [format] - Export format (yaml or json) * @param {string} [outputPath] - Optional path for export files * @returns {MetadataExportResult} Result object with list of exported files * @example * ```typescript * import { exportMetadata } from './metadata-exporter.js'; * * // Basic metadata export * const metadata = { * title: 'Service Agreement', * author: 'Legal Team', * version: '1.0', * date: '2023-01-01' * }; * * const result = exportMetadata(metadata, 'yaml', './output'); * console.log('Exported to:', result.exportedFiles); * * // Export with custom filenames * const customMetadata = { * title: 'Contract', * 'meta-yaml-output': 'contract-metadata.yaml', * 'meta-json-output': 'contract-metadata.json', * 'meta-output-path': './custom-output' * }; * * const customResult = exportMetadata(customMetadata); * ``` */ export function exportMetadata(metadata, format, outputPath) { const exportedFiles = []; // Extract export configuration from metadata const yamlOutput = metadata['meta-yaml-output']; const jsonOutput = metadata['meta-json-output']; const customOutputPath = metadata['meta-output-path']; // Determine output directory - if outputPath is a file, use its directory let outputDir; if (customOutputPath) { outputDir = customOutputPath; } else if (outputPath) { // Check if outputPath looks like a file (has extension) or directory outputDir = path.extname(outputPath) ? path.dirname(outputPath) : outputPath; } else { outputDir = process.cwd(); } // Create output directory if it doesn't exist if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } // Process metadata for export (remove internal keys) const exportedMetadata = filterMetadataForExport(metadata); // Process YAML output if specified if (yamlOutput || format === 'yaml') { let yamlPath; if (yamlOutput) { yamlPath = path.resolve(outputDir, yamlOutput); } else if (outputPath && path.extname(outputPath)) { // If outputPath is a complete file path, use it directly yamlPath = outputPath; } else { yamlPath = path.resolve(outputDir, 'metadata.yaml'); } try { // Ensure directory exists const yamlDir = path.dirname(yamlPath); if (!fs.existsSync(yamlDir)) { fs.mkdirSync(yamlDir, { recursive: true }); } const yamlContent = yaml.dump(exportedMetadata); fs.writeFileSync(yamlPath, yamlContent, 'utf8'); exportedFiles.push(yamlPath); logger.debug(`Exported YAML metadata to: ${yamlPath}`); } catch (error) { logger.error('Error exporting YAML metadata:', error instanceof Error ? error.message : String(error)); } } // Process JSON output if specified if (jsonOutput || format === 'json') { const jsonPath = jsonOutput ? path.resolve(outputDir, jsonOutput) : path.resolve(outputDir, 'metadata.json'); try { // Ensure directory exists const jsonDir = path.dirname(jsonPath); if (!fs.existsSync(jsonDir)) { fs.mkdirSync(jsonDir, { recursive: true }); } const jsonContent = JSON.stringify(exportedMetadata, null, 2); fs.writeFileSync(jsonPath, jsonContent, 'utf8'); exportedFiles.push(jsonPath); logger.debug(`Exported JSON metadata to: ${jsonPath}`); } catch (error) { logger.error('Error exporting JSON metadata:', error instanceof Error ? error.message : String(error)); } } return { exportedFiles }; } /** * Filters metadata based on export configuration * * Processes metadata to remove internal configuration keys and applies filtering * rules based on export settings. This ensures that only relevant metadata is * included in the exported files. * * @function filterMetadataForExport * @param {Record<string, any>} metadata - Complete metadata object to filter * @returns {Record<string, any>} Filtered metadata object suitable for export * @example * ```typescript * import { filterMetadataForExport } from './metadata-exporter.js'; * * const metadata = { * title: 'Legal Agreement', * author: 'Legal Team', * 'meta-yaml-output': 'output.yaml', * 'meta-json-output': 'output.json', * 'meta-output-path': './exports', * 'meta-include-original': false * }; * * const filtered = filterMetadataForExport(metadata); * // Result: { title: 'Legal Agreement', author: 'Legal Team' } * // Internal meta-* keys are removed * ``` */ export function filterMetadataForExport(metadata) { // Deep clone the metadata to avoid modifying original const result = JSON.parse(JSON.stringify(metadata)); // Remove internal export configuration keys delete result['meta-yaml-output']; delete result['meta-json-output']; delete result['meta-output-path']; delete result['meta-include-original']; // Check if we should include only keys under 'meta' if (metadata['meta-include-original'] === false && metadata['meta']) { return { meta: result.meta }; } return result; } //# sourceMappingURL=metadata-exporter.js.map