UNPKG

legal-markdown-js

Version:

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

410 lines 19.1 kB
"use strict"; /** * Main Entry Point for Legal Markdown Processing Library * * This module provides the primary API for processing Legal Markdown documents * with support for YAML front matter, cross-references, optional clauses, mixins, * header processing, and multi-format output generation (HTML, PDF, DOCX). * * Features: * - YAML front matter parsing and metadata extraction * - Cross-reference processing and resolution * - Optional clause conditional rendering * - Mixin system for reusable content blocks * - Header numbering and formatting * - Field tracking for document highlighting * - HTML, PDF, and DOCX generation with styling * - RST and LaTeX preprocessing support * - Metadata export capabilities * * @example * ```typescript * import { processLegalMarkdown, generateHtml, generatePdf } from 'legal-markdown-js'; * * // Basic document processing * const result = await processLegalMarkdown(content, { * enableFieldTracking: true, * basePath: './documents' * }); * * // Generate HTML output * const html = await generateHtml(content, { * title: 'Legal Agreement', * includeHighlighting: true * }); * * // Generate PDF output * const pdf = await generatePdf(content, './output.pdf', { * format: 'A4', * includeHighlighting: true * }); * ``` */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.docxGenerator = exports.pdfGenerator = exports.htmlGenerator = exports.fieldTracker = exports.processLegalMarkdown = void 0; exports.generateHtml = generateHtml; exports.generatePdf = generatePdf; exports.generatePdfVersions = generatePdfVersions; exports.generateDocx = generateDocx; exports.generateDocxVersions = generateDocxVersions; const html_generator_1 = require("./extensions/generators/html-generator"); const pdf_generator_1 = require("./extensions/generators/pdf-generator"); const legal_markdown_processor_1 = require("./extensions/remark/legal-markdown-processor"); const docx_generator_1 = require("./extensions/generators/docx-generator"); const pdf_connectors_1 = require("./extensions/generators/pdf-connectors"); const fs = __importStar(require("fs/promises")); const path_1 = __importDefault(require("path")); /** * Process Legal Markdown content using the canonical async remark pipeline. * * @param content - Raw Legal Markdown document content. * @param options - Optional processing settings for parsing, plugins, tracking, and exports. * @returns Promise resolving to processed markdown, metadata, and optional tracking statistics. * @throws {ValidationError | PipelineError | ParseError | ImportError | ProcessingError | YamlParsingError | PdfDependencyError} * Throws typed processing errors when parsing, import resolution, or pipeline execution fails. * @example * ```typescript * import { processLegalMarkdown } from 'legal-markdown-js'; * * const result = await processLegalMarkdown(markdown, { * basePath: './docs', * enableFieldTracking: true, * }); * * console.log(result.content); * ``` */ exports.processLegalMarkdown = legal_markdown_processor_1.processLegalMarkdown; /** * Generate HTML from Legal Markdown content * * This function processes Legal Markdown content and generates a complete HTML * document with styling, field highlighting, and responsive design features. * It combines the Legal Markdown processing pipeline with HTML generation. * * @param {string} content - The raw Legal Markdown content to convert * @param {LegalMarkdownOptions & Object} [options={}] - Configuration options * @param {string} [options.cssPath] - Path to custom CSS file * @param {string} [options.highlightCssPath] - Path to field highlighting CSS * @param {boolean} [options.includeHighlighting] - Whether to include field highlighting * @param {string} [options.title] - Document title for HTML * @returns {Promise<string>} A promise that resolves to the complete HTML document * @throws {Error} When HTML generation fails * @example * ```typescript * const html = await generateHtml(content, { * title: 'Service Agreement', * cssPath: './custom-styles.css', * includeHighlighting: true, * enableFieldTracking: true * }); * ``` */ async function generateHtml(content, options = {}) { try { // Always use remark processor for HTML generation to ensure field tracking works // Field tracking is essential for HTML structure (headers, mixins, etc.) const result = await (0, exports.processLegalMarkdown)(content, { ...options, enableFieldTracking: true, // Always enabled for HTML generation (structure) debug: options.debug || false, }); return html_generator_1.htmlGenerator.generateHtml(result.content, { cssPath: options.cssPath, highlightCssPath: options.highlightCssPath || path_1.default.join(process.cwd(), 'src/styles/highlight.css'), includeHighlighting: options.includeHighlighting, title: options.title || (typeof result.metadata?.title === 'string' ? result.metadata.title : undefined), metadata: result.metadata, }); } catch (error) { console.warn('HTML generation pipeline failed, falling back to legacy processing:', error); return generateHtmlLegacy(content, options); } } /** * Legacy HTML generation as fallback */ async function generateHtmlLegacy(content, options = {}) { // Process the legal markdown first (use async version for better RST/LaTeX support) const processed = await (0, exports.processLegalMarkdown)(content, { ...options, enableFieldTracking: true, }); // Generate HTML return html_generator_1.htmlGenerator.generateHtml(processed.content, { cssPath: options.cssPath, highlightCssPath: options.highlightCssPath || path_1.default.join(process.cwd(), 'src/styles/highlight.css'), includeHighlighting: options.includeHighlighting, title: options.title, metadata: processed.metadata, }); } async function generatePdfFromProcessedMarkdown(processedContent, outputPath, metadata, options) { const connectorPreference = options.pdfConnector ?? 'auto'; const connector = await (0, pdf_connectors_1.resolvePdfConnector)(connectorPreference); const title = options.title || (typeof metadata?.title === 'string' ? metadata.title : undefined); // Keep historical behavior for the Puppeteer connector, including template handling. if (connector.name === 'puppeteer') { return pdf_generator_1.pdfGenerator.generatePdf(processedContent, outputPath, { cssPath: options.cssPath, highlightCssPath: options.highlightCssPath || path_1.default.join(process.cwd(), 'src/styles/highlight.css'), includeHighlighting: options.includeHighlighting, title, metadata, format: options.format, landscape: options.landscape, headerTemplate: options.headerTemplate, footerTemplate: options.footerTemplate, }); } const html = await html_generator_1.htmlGenerator.generateHtml(processedContent, { cssPath: options.cssPath, highlightCssPath: options.highlightCssPath || path_1.default.join(process.cwd(), 'src/styles/highlight.css'), includeHighlighting: options.includeHighlighting, title, metadata, }); const pdfOptions = { format: options.format || 'A4', margin: { top: '1cm', right: '1cm', bottom: '1cm', left: '1cm', }, landscape: options.landscape, headerTemplate: options.headerTemplate, footerTemplate: options.footerTemplate, }; await connector.generatePdf(html, outputPath, pdfOptions); return fs.readFile(outputPath); } /** * Generate PDF from Legal Markdown content * * This function processes Legal Markdown content and generates a PDF document * with professional styling, field highlighting, and customizable page formatting. * It combines the Legal Markdown processing pipeline with PDF generation. * * @param {string} content - The raw Legal Markdown content to convert * @param {string} outputPath - File path where the PDF will be saved * @param {LegalMarkdownOptions & Object} [options={}] - Configuration options * @param {string} [options.cssPath] - Path to custom CSS file * @param {string} [options.highlightCssPath] - Path to field highlighting CSS * @param {boolean} [options.includeHighlighting] - Whether to include field highlighting * @param {string} [options.title] - Document title for PDF * @param {'A4' | 'Letter' | 'Legal'} [options.format] - Page format * @param {boolean} [options.landscape] - Whether to use landscape orientation * @param {'auto' | 'puppeteer' | 'system-chrome' | 'weasyprint'} [options.pdfConnector] - PDF backend connector * @returns {Promise<Buffer>} A promise that resolves to the PDF buffer * @throws {Error} When PDF generation fails * @example * ```typescript * const pdf = await generatePdf(content, './contract.pdf', { * title: 'Service Agreement', * format: 'A4', * includeHighlighting: true, * enableFieldTracking: true * }); * ``` */ async function generatePdf(content, outputPath, options = {}) { try { // Always use remark processor for PDF generation to ensure field tracking works // Field tracking is essential for PDF structure (headers, mixins, cross-references) const result = await (0, exports.processLegalMarkdown)(content, { ...options, enableFieldTracking: true, // Always enabled for PDF generation (structure) debug: options.debug || false, }); return generatePdfFromProcessedMarkdown(result.content, outputPath, result.metadata, options); } catch (error) { console.warn('PDF generation pipeline failed, falling back to legacy processing:', error); return generatePdfLegacy(content, outputPath, options); } } /** * Legacy PDF generation as fallback */ async function generatePdfLegacy(content, outputPath, options = {}) { // Process the legal markdown first (use async version for better RST/LaTeX support) const processed = await (0, exports.processLegalMarkdown)(content, { ...options, enableFieldTracking: true, }); return generatePdfFromProcessedMarkdown(processed.content, outputPath, processed.metadata, options); } /** * Generate both normal and highlighted PDF versions * * This function creates two PDF versions of the same Legal Markdown document: * one with standard formatting and another with field highlighting enabled. * This is useful for document review processes where both clean and annotated * versions are needed. * * @param {string} content - The raw Legal Markdown content to convert * @param {string} outputPath - Base file path for PDFs (will be modified for each version) * @param {LegalMarkdownOptions & Object} [options={}] - Configuration options * @param {string} [options.cssPath] - Path to custom CSS file * @param {string} [options.highlightCssPath] - Path to field highlighting CSS * @param {string} [options.title] - Document title for PDFs * @param {'A4' | 'Letter' | 'Legal'} [options.format] - Page format * @param {boolean} [options.landscape] - Whether to use landscape orientation * @param {'auto' | 'puppeteer' | 'system-chrome' | 'weasyprint'} [options.pdfConnector] - PDF backend connector * @returns {Promise<Object>} A promise that resolves to both PDF buffers * @returns {Buffer} returns.normal - The normal PDF without highlighting * @returns {Buffer} returns.highlighted - The highlighted PDF with field annotations * @throws {Error} When PDF generation fails * @example * ```typescript * const { normal, highlighted } = await generatePdfVersions(content, './contract.pdf', { * title: 'Service Agreement', * format: 'A4' * }); * // Creates: contract.pdf and contract.HIGHLIGHT.pdf * ``` */ async function generatePdfVersions(content, outputPath, options = {}) { const normalPath = outputPath; const highlightedPath = outputPath.replace('.pdf', '.HIGHLIGHT.pdf'); const [normal, highlighted] = await Promise.all([ generatePdf(content, normalPath, { ...options, includeHighlighting: false }), generatePdf(content, highlightedPath, { ...options, includeHighlighting: true }), ]); return { normal, highlighted }; } /** * Generate DOCX from Legal Markdown content * * @param {string} content - The raw Legal Markdown content to convert * @param {string} outputPath - File path where the DOCX will be saved * @param {LegalMarkdownOptions & Object} [options={}] - Configuration options * @param {string} [options.cssPath] - Path to custom CSS file * @param {string} [options.highlightCssPath] - Path to field highlighting CSS * @param {boolean} [options.includeHighlighting] - Whether to include field highlighting * @param {string} [options.title] - Document title for DOCX * @param {'A4' | 'Letter' | 'Legal'} [options.format] - Page format * @param {boolean} [options.landscape] - Whether to use landscape orientation * @returns {Promise<Buffer>} A promise that resolves to the DOCX buffer * @throws {Error} When DOCX generation fails */ async function generateDocx(content, outputPath, options = {}) { try { const result = await (0, exports.processLegalMarkdown)(content, { ...options, enableFieldTracking: true, debug: options.debug || false, }); return docx_generator_1.docxGenerator.generateDocx(result.content, outputPath, { cssPath: options.cssPath, highlightCssPath: options.highlightCssPath || path_1.default.join(process.cwd(), 'src/styles/highlight.css'), includeHighlighting: options.includeHighlighting, title: options.title || (typeof result.metadata?.title === 'string' ? result.metadata.title : undefined), metadata: result.metadata, format: options.format, landscape: options.landscape, basePath: options.basePath, headerTemplate: options.headerTemplate, footerTemplate: options.footerTemplate, version: typeof result.metadata?.version === 'string' ? result.metadata.version : undefined, }); } catch (error) { console.warn('DOCX generation pipeline failed, falling back to legacy processing:', error); return generateDocxLegacy(content, outputPath, options); } } /** * Legacy DOCX generation as fallback */ async function generateDocxLegacy(content, outputPath, options = {}) { const processed = await (0, exports.processLegalMarkdown)(content, { ...options, enableFieldTracking: true, }); return docx_generator_1.docxGenerator.generateDocx(processed.content, outputPath, { cssPath: options.cssPath, highlightCssPath: options.highlightCssPath || path_1.default.join(process.cwd(), 'src/styles/highlight.css'), includeHighlighting: options.includeHighlighting, title: options.title, metadata: processed.metadata, format: options.format, landscape: options.landscape, basePath: options.basePath, headerTemplate: options.headerTemplate, footerTemplate: options.footerTemplate, version: typeof processed.metadata?.version === 'string' ? processed.metadata.version : undefined, }); } /** * Generate both normal and highlighted DOCX versions */ async function generateDocxVersions(content, outputPath, options = {}) { const normalPath = outputPath; const highlightedPath = outputPath.replace('.docx', '.HIGHLIGHT.docx'); const [normal, highlighted] = await Promise.all([ generateDocx(content, normalPath, { ...options, includeHighlighting: false }), generateDocx(content, highlightedPath, { ...options, includeHighlighting: true }), ]); return { normal, highlighted }; } // Export all sub-modules __exportStar(require("./types"), exports); __exportStar(require("./core/index"), exports); __exportStar(require("./errors/index"), exports); __exportStar(require("./constants/index"), exports); __exportStar(require("./utils/index"), exports); __exportStar(require("./extensions/index"), exports); // Specific re-exports to avoid conflicts (extensions take precedence) var field_tracker_1 = require("./extensions/tracking/field-tracker"); Object.defineProperty(exports, "fieldTracker", { enumerable: true, get: function () { return field_tracker_1.fieldTracker; } }); var html_generator_2 = require("./extensions/generators/html-generator"); Object.defineProperty(exports, "htmlGenerator", { enumerable: true, get: function () { return html_generator_2.htmlGenerator; } }); var pdf_generator_2 = require("./extensions/generators/pdf-generator"); Object.defineProperty(exports, "pdfGenerator", { enumerable: true, get: function () { return pdf_generator_2.pdfGenerator; } }); var docx_generator_2 = require("./extensions/generators/docx-generator"); Object.defineProperty(exports, "docxGenerator", { enumerable: true, get: function () { return docx_generator_2.docxGenerator; } }); //# sourceMappingURL=index.js.map