legal-markdown-js 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,8 +5,8 @@
5
5
  > feature parity.
6
6
 
7
7
  Process markdown with YAML front matter, conditional clauses
8
- `[text]{condition}`, cross-references `|variable|`, imports `@import`, and
9
- generate professional PDFs ready to be shared.
8
+ `[text]{condition}`, cross-references `|reference|`, mixins `{{variable}}`,
9
+ imports `@import`, and generate professional PDFs ready to be shared.
10
10
 
11
11
  ![Legal Markdown JS Example](docs/legal-markdown-js-example.png)
12
12
 
@@ -84,8 +84,7 @@ All original Legal Markdown features are fully implemented:
84
84
  `lll.`)
85
85
  - **Optional Clauses**: Boolean, equality, and logical operations
86
86
  (`[text]{condition}`)
87
- - **Cross-References**: All reference types including special date handling
88
- (`|reference|`)
87
+ - **Cross-References**: Internal section references using (`|reference|`) syntax
89
88
  - **Partial Imports**: File inclusion with path resolution (`@import`)
90
89
  - **Metadata Export**: YAML and JSON export with custom paths
91
90
 
@@ -93,7 +92,8 @@ All original Legal Markdown features are fully implemented:
93
92
 
94
93
  Additional features available only in the Node.js version:
95
94
 
96
- - **Mixins System**: Template substitution with `{{variable}}` syntax
95
+ - **Mixins System**: Template substitution and helpers with `{{variable}}`
96
+ syntax
97
97
  - **PDF Generation**: Professional PDF output with styling and field
98
98
  highlighting
99
99
  - **HTML Generation**: Custom HTML output with CSS support
@@ -1,115 +1,69 @@
1
1
  /**
2
2
  * @fileoverview Cross-Reference Processing Module for Legal Markdown Documents
3
3
  *
4
- * This module provides functionality to process cross-references in Legal Markdown
5
- * documents, replacing reference placeholders with actual values from metadata.
6
- * It supports various formatting options including date formatting, currency
7
- * formatting, and nested metadata access through dot notation.
4
+ * This module provides functionality to process internal cross-references in Legal Markdown
5
+ * documents, allowing sections to reference other sections by their keys.
6
+ * Based on the original Ruby Legal Markdown specification.
8
7
  *
9
8
  * Features:
10
- * - Cross-reference syntax: |reference_key|
11
- * - Date reference processing with @today support
12
- * - Automatic currency formatting for amount fields
13
- * - Nested metadata value access with dot notation
14
- * - Type-aware value formatting (dates, numbers, strings)
15
- * - Fallback to original reference if value not found
16
- * - Integration with date-processor for date handling
9
+ * - Internal cross-reference syntax: |reference_key|
10
+ * - Automatic section numbering and reference resolution
11
+ * - Reference capture from headers with |key| syntax
12
+ * - Section reference replacement throughout the document
13
+ * - Compatible with legal document numbering (l., ll., lll.)
17
14
  *
18
15
  * @example
19
16
  * ```typescript
20
17
  * import { processCrossReferences } from './reference-processor';
21
18
  *
22
19
  * const content = `
23
- * This agreement is between |client.name| and |provider.name|.
24
- * The total amount is |contract.amount| due on |contract.due_date|.
25
- * Document generated on |@today|.
26
- * `;
20
+ * l. **Definitions** |definitions|
21
+ *
22
+ * Terms defined in |definitions| apply throughout this agreement.
27
23
  *
28
- * const metadata = {
29
- * client: { name: "Acme Corp" },
30
- * provider: { name: "Service Ltd" },
31
- * contract: {
32
- * amount: 25000,
33
- * due_date: new Date("2024-12-31")
34
- * },
35
- * payment_currency: "USD"
36
- * };
24
+ * l. **Payment Terms** |payment|
37
25
  *
38
- * const processed = processCrossReferences(content, metadata);
26
+ * As outlined in |payment|, payment is due within 30 days.
27
+ * Reference to |definitions| for term meanings.
28
+ * `;
29
+ *
30
+ * const processed = processCrossReferences(content, {});
39
31
  * console.log(processed);
40
32
  * // Output:
41
- * // This agreement is between Acme Corp and Service Ltd.
42
- * // The total amount is $25,000.00 due on 2024-12-31.
43
- * // Document generated on 2024-01-15.
33
+ * // Article 1. **Definitions**
34
+ * //
35
+ * // Terms defined in Article 1 apply throughout this agreement.
36
+ * //
37
+ * // Article 2. **Payment Terms**
38
+ * //
39
+ * // As outlined in Article 2, payment is due within 30 days.
40
+ * // Reference to Article 1 for term meanings.
44
41
  * ```
45
42
  */
46
43
  /**
47
- * Processes cross-references in a LegalMarkdown document
44
+ * Processes internal cross-references in a Legal Markdown document
48
45
  *
49
- * This is the main function that processes cross-references using the |reference_key|
50
- * syntax. It first processes date references, then handles regular cross-references
51
- * with automatic formatting based on value type and field names.
46
+ * This function implements a hybrid approach:
47
+ * 1. First tries to resolve |key| as internal section references (Ruby spec)
48
+ * 2. Falls back to metadata values for backward compatibility
52
49
  *
53
50
  * @param {string} content - The document content containing cross-references
54
- * @param {Record<string, any>} metadata - Document metadata with reference values
55
- * @returns {string} Processed content with references replaced by their values
51
+ * @param {Record<string, any>} metadata - Document metadata (used for level formatting and fallback)
52
+ * @returns {string} Processed content with internal references resolved
56
53
  * @example
57
54
  * ```typescript
58
- * // Basic reference processing
59
- * const content = "Payment due: |payment.amount| on |payment.date|";
60
- * const metadata = {
61
- * payment: {
62
- * amount: 1500,
63
- * date: new Date("2024-03-15")
64
- * },
65
- * payment_currency: "EUR"
66
- * };
67
- *
68
- * const result = processCrossReferences(content, metadata);
69
- * // Output: "Payment due: €1,500.00 on 2024-03-15"
55
+ * const content = `
56
+ * l. **Contract Terms** |terms|
70
57
  *
71
- * // Nested reference access
72
- * const content2 = "Contact: |client.contact.email| (|client.contact.phone|)";
73
- * const metadata2 = {
74
- * client: {
75
- * contact: {
76
- * email: "info@client.com",
77
- * phone: "+1-555-0123"
78
- * }
79
- * }
80
- * };
58
+ * As specified in |terms|, this agreement is binding.
59
+ * Reference to |client_name| from metadata.
60
+ * `;
81
61
  *
82
- * const result2 = processCrossReferences(content2, metadata2);
83
- * // Output: "Contact: info@client.com (+1-555-0123)"
62
+ * const metadata = { client_name: "ACME Corp" };
63
+ * const result = processCrossReferences(content, metadata);
64
+ * // |terms| -> "Article 1." (internal reference)
65
+ * // |client_name| -> "ACME Corp" (metadata fallback)
84
66
  * ```
85
67
  */
86
68
  export declare function processCrossReferences(content: string, metadata: Record<string, any>): string;
87
- /**
88
- * Processes special reference formats like dates and currency amounts
89
- *
90
- * Applies appropriate formatting to reference values based on their type and
91
- * optional format specifiers. Handles dates, currency amounts, and falls back
92
- * to string conversion for other types.
93
- *
94
- * @param {any} value - The reference value to format
95
- * @param {string} [format] - Optional format specifier (e.g., "currency:USD:en-US")
96
- * @returns {string} Formatted value as string
97
- * @example
98
- * ```typescript
99
- * // Date formatting
100
- * const date = new Date("2024-03-15");
101
- * console.log(formatReferenceValue(date)); // "2024-03-15"
102
- * console.log(formatReferenceValue(date, "long")); // "March 15, 2024"
103
- * console.log(formatReferenceValue(date, "short")); // "3/15/2024"
104
- *
105
- * // Currency formatting
106
- * console.log(formatReferenceValue(1500, "currency:USD")); // "$1,500.00"
107
- * console.log(formatReferenceValue(1500, "currency:EUR:de-DE")); // "1.500,00 €"
108
- *
109
- * // Default string conversion
110
- * console.log(formatReferenceValue("Hello World")); // "Hello World"
111
- * console.log(formatReferenceValue(12345)); // "12345"
112
- * ```
113
- */
114
- export declare function formatReferenceValue(value: any, format?: string): string;
115
69
  //# sourceMappingURL=reference-processor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reference-processor.d.ts","sourceRoot":"","sources":["../../../src/core/processors/reference-processor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CA4B7F;AA6CD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAgBxE"}
1
+ {"version":3,"file":"reference-processor.d.ts","sourceRoot":"","sources":["../../../src/core/processors/reference-processor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAWH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAM7F"}
@@ -2,144 +2,194 @@
2
2
  /**
3
3
  * @fileoverview Cross-Reference Processing Module for Legal Markdown Documents
4
4
  *
5
- * This module provides functionality to process cross-references in Legal Markdown
6
- * documents, replacing reference placeholders with actual values from metadata.
7
- * It supports various formatting options including date formatting, currency
8
- * formatting, and nested metadata access through dot notation.
5
+ * This module provides functionality to process internal cross-references in Legal Markdown
6
+ * documents, allowing sections to reference other sections by their keys.
7
+ * Based on the original Ruby Legal Markdown specification.
9
8
  *
10
9
  * Features:
11
- * - Cross-reference syntax: |reference_key|
12
- * - Date reference processing with @today support
13
- * - Automatic currency formatting for amount fields
14
- * - Nested metadata value access with dot notation
15
- * - Type-aware value formatting (dates, numbers, strings)
16
- * - Fallback to original reference if value not found
17
- * - Integration with date-processor for date handling
10
+ * - Internal cross-reference syntax: |reference_key|
11
+ * - Automatic section numbering and reference resolution
12
+ * - Reference capture from headers with |key| syntax
13
+ * - Section reference replacement throughout the document
14
+ * - Compatible with legal document numbering (l., ll., lll.)
18
15
  *
19
16
  * @example
20
17
  * ```typescript
21
18
  * import { processCrossReferences } from './reference-processor';
22
19
  *
23
20
  * const content = `
24
- * This agreement is between |client.name| and |provider.name|.
25
- * The total amount is |contract.amount| due on |contract.due_date|.
26
- * Document generated on |@today|.
27
- * `;
21
+ * l. **Definitions** |definitions|
22
+ *
23
+ * Terms defined in |definitions| apply throughout this agreement.
28
24
  *
29
- * const metadata = {
30
- * client: { name: "Acme Corp" },
31
- * provider: { name: "Service Ltd" },
32
- * contract: {
33
- * amount: 25000,
34
- * due_date: new Date("2024-12-31")
35
- * },
36
- * payment_currency: "USD"
37
- * };
25
+ * l. **Payment Terms** |payment|
38
26
  *
39
- * const processed = processCrossReferences(content, metadata);
27
+ * As outlined in |payment|, payment is due within 30 days.
28
+ * Reference to |definitions| for term meanings.
29
+ * `;
30
+ *
31
+ * const processed = processCrossReferences(content, {});
40
32
  * console.log(processed);
41
33
  * // Output:
42
- * // This agreement is between Acme Corp and Service Ltd.
43
- * // The total amount is $25,000.00 due on 2024-12-31.
44
- * // Document generated on 2024-01-15.
34
+ * // Article 1. **Definitions**
35
+ * //
36
+ * // Terms defined in Article 1 apply throughout this agreement.
37
+ * //
38
+ * // Article 2. **Payment Terms**
39
+ * //
40
+ * // As outlined in Article 2, payment is due within 30 days.
41
+ * // Reference to Article 1 for term meanings.
45
42
  * ```
46
43
  */
47
44
  Object.defineProperty(exports, "__esModule", { value: true });
48
45
  exports.processCrossReferences = processCrossReferences;
49
- exports.formatReferenceValue = formatReferenceValue;
50
- const date_processor_1 = require("./date-processor");
51
46
  /**
52
- * Processes cross-references in a LegalMarkdown document
47
+ * Processes internal cross-references in a Legal Markdown document
53
48
  *
54
- * This is the main function that processes cross-references using the |reference_key|
55
- * syntax. It first processes date references, then handles regular cross-references
56
- * with automatic formatting based on value type and field names.
49
+ * This function implements a hybrid approach:
50
+ * 1. First tries to resolve |key| as internal section references (Ruby spec)
51
+ * 2. Falls back to metadata values for backward compatibility
57
52
  *
58
53
  * @param {string} content - The document content containing cross-references
59
- * @param {Record<string, any>} metadata - Document metadata with reference values
60
- * @returns {string} Processed content with references replaced by their values
54
+ * @param {Record<string, any>} metadata - Document metadata (used for level formatting and fallback)
55
+ * @returns {string} Processed content with internal references resolved
61
56
  * @example
62
57
  * ```typescript
63
- * // Basic reference processing
64
- * const content = "Payment due: |payment.amount| on |payment.date|";
65
- * const metadata = {
66
- * payment: {
67
- * amount: 1500,
68
- * date: new Date("2024-03-15")
69
- * },
70
- * payment_currency: "EUR"
71
- * };
72
- *
73
- * const result = processCrossReferences(content, metadata);
74
- * // Output: "Payment due: €1,500.00 on 2024-03-15"
58
+ * const content = `
59
+ * l. **Contract Terms** |terms|
75
60
  *
76
- * // Nested reference access
77
- * const content2 = "Contact: |client.contact.email| (|client.contact.phone|)";
78
- * const metadata2 = {
79
- * client: {
80
- * contact: {
81
- * email: "info@client.com",
82
- * phone: "+1-555-0123"
83
- * }
84
- * }
85
- * };
61
+ * As specified in |terms|, this agreement is binding.
62
+ * Reference to |client_name| from metadata.
63
+ * `;
86
64
  *
87
- * const result2 = processCrossReferences(content2, metadata2);
88
- * // Output: "Contact: info@client.com (+1-555-0123)"
65
+ * const metadata = { client_name: "ACME Corp" };
66
+ * const result = processCrossReferences(content, metadata);
67
+ * // |terms| -> "Article 1." (internal reference)
68
+ * // |client_name| -> "ACME Corp" (metadata fallback)
89
69
  * ```
90
70
  */
91
71
  function processCrossReferences(content, metadata) {
92
- // First process date references (@today)
93
- const processedContent = (0, date_processor_1.processDateReferences)(content, metadata);
94
- // Then process regular cross-references
95
- // Format: |reference_key|
96
- const referencePattern = /\|(.*?)\|/g;
97
- return processedContent.replace(referencePattern, (match, key) => {
98
- // Get the reference value from metadata
99
- const value = getNestedValue(metadata, key.trim());
100
- if (value === undefined) {
101
- return match;
102
- }
103
- // Format value based on type
104
- if (value instanceof Date) {
105
- return formatDate(value);
106
- }
107
- else if (typeof value === 'number' && key.includes('amount')) {
108
- // Format currency if key contains 'amount'
109
- const currency = metadata.payment_currency || 'USD';
110
- return formatCurrency(value, `currency:${currency}`);
111
- }
112
- // Default string conversion
113
- return String(value);
114
- });
72
+ // First, extract all cross-reference definitions from headers
73
+ const crossReferences = extractCrossReferences(content, metadata);
74
+ // Then replace all cross-reference usage with section numbers or metadata
75
+ return replaceCrossReferences(content, crossReferences, metadata);
115
76
  }
116
77
  /**
117
- * Gets a potentially nested value from an object
78
+ * Extracts cross-reference definitions from headers in the document
118
79
  *
119
- * Traverses an object using dot notation to access nested properties safely.
120
- * Returns undefined if any part of the path doesn't exist, preventing errors
121
- * when accessing deeply nested properties.
80
+ * Scans the document for headers containing |key| syntax and captures
81
+ * their section numbers after header processing. This creates a mapping
82
+ * of reference keys to their section identifiers.
122
83
  *
123
84
  * @private
124
- * @param {Record<string, any>} obj - Object to extract value from
125
- * @param {string} path - Dot-separated path to the value (e.g., "user.profile.name")
126
- * @returns {any} The value at the specified path, or undefined if not found
127
- * @example
128
- * ```typescript
129
- * const obj = {
130
- * contract: {
131
- * parties: {
132
- * client: { name: "Acme Corp", id: 12345 },
133
- * provider: { name: "Service Ltd" }
134
- * },
135
- * terms: { duration: 12 }
136
- * }
137
- * };
85
+ * @param {string} content - Document content to scan for cross-references
86
+ * @param {Record<string, any>} metadata - Metadata for level formatting
87
+ * @returns {CrossReference[]} Array of cross-reference mappings
88
+ */
89
+ function extractCrossReferences(content, metadata) {
90
+ const crossReferences = [];
91
+ const lines = content.split('\n');
92
+ // Track section counters for each level
93
+ const sectionCounters = { level1: 0, level2: 0, level3: 0 };
94
+ // Get level formats from metadata
95
+ const levelFormats = {
96
+ level1: metadata['level-one'] || 'Article %n.',
97
+ level2: metadata['level-two'] || 'Section %n.',
98
+ level3: metadata['level-three'] || '(%n)',
99
+ };
100
+ for (const line of lines) {
101
+ const trimmedLine = line.trim();
102
+ // Check for header lines with cross-reference keys
103
+ const headerMatch = trimmedLine.match(/^(l{1,3})\.\s+(.+?)\s+\|(\w+)\|$/);
104
+ if (headerMatch) {
105
+ const [, levelMarker, headerText, key] = headerMatch;
106
+ const level = levelMarker.length;
107
+ // Update section counters
108
+ if (level === 1) {
109
+ sectionCounters.level1++;
110
+ sectionCounters.level2 = 0; // Reset level 2 counter
111
+ sectionCounters.level3 = 0; // Reset level 3 counter
112
+ }
113
+ else if (level === 2) {
114
+ sectionCounters.level2++;
115
+ sectionCounters.level3 = 0; // Reset level 3 counter
116
+ }
117
+ else if (level === 3) {
118
+ sectionCounters.level3++;
119
+ }
120
+ // Generate section number based on level
121
+ let sectionNumber;
122
+ let sectionText;
123
+ if (level === 1) {
124
+ sectionNumber = levelFormats.level1.replace(/%n/g, sectionCounters.level1.toString());
125
+ sectionText = `${sectionNumber} ${headerText}`;
126
+ }
127
+ else if (level === 2) {
128
+ sectionNumber = levelFormats.level2.replace(/%n/g, sectionCounters.level2.toString());
129
+ sectionText = `${sectionNumber} ${headerText}`;
130
+ }
131
+ else {
132
+ sectionNumber = levelFormats.level3.replace(/%n/g, sectionCounters.level3.toString());
133
+ sectionText = `${sectionNumber} ${headerText}`;
134
+ }
135
+ crossReferences.push({
136
+ key,
137
+ sectionNumber: sectionNumber.trim(),
138
+ sectionText: sectionText.trim(),
139
+ });
140
+ }
141
+ }
142
+ return crossReferences;
143
+ }
144
+ /**
145
+ * Replaces cross-reference usage throughout the document
138
146
  *
139
- * console.log(getNestedValue(obj, "contract.parties.client.name")); // "Acme Corp"
140
- * console.log(getNestedValue(obj, "contract.terms.duration")); // 12
141
- * console.log(getNestedValue(obj, "contract.nonexistent")); // undefined
142
- * ```
147
+ * Scans the document for |key| references and replaces them with:
148
+ * 1. Section numbers from internal cross-references (priority)
149
+ * 2. Metadata values as fallback for backward compatibility
150
+ * 3. Original reference if neither is found
151
+ *
152
+ * @private
153
+ * @param {string} content - Document content to process
154
+ * @param {CrossReference[]} crossReferences - Map of keys to section numbers
155
+ * @param {Record<string, any>} metadata - Metadata for fallback resolution
156
+ * @returns {string} Document with cross-references replaced
157
+ */
158
+ function replaceCrossReferences(content, crossReferences, metadata) {
159
+ // Create a map for quick lookups
160
+ const referenceMap = new Map();
161
+ for (const ref of crossReferences) {
162
+ referenceMap.set(ref.key, ref.sectionNumber);
163
+ }
164
+ // Replace all |key| references (except those in headers which define them)
165
+ const lines = content.split('\n');
166
+ const processedLines = lines.map(line => {
167
+ const trimmedLine = line.trim();
168
+ // Skip lines that define cross-references (headers with |key| syntax)
169
+ if (trimmedLine.match(/^(l{1,3})\.\s+(.+?)\s+\|(\w+)\|$/)) {
170
+ return line;
171
+ }
172
+ // Process cross-reference usage in content lines
173
+ return line.replace(/\|([^|]+)\|/g, (match, key) => {
174
+ const trimmedKey = key.trim();
175
+ // First try internal section reference
176
+ const sectionNumber = referenceMap.get(trimmedKey);
177
+ if (sectionNumber) {
178
+ return sectionNumber;
179
+ }
180
+ // Fallback to metadata value
181
+ const metadataValue = getNestedValue(metadata, trimmedKey);
182
+ if (metadataValue !== undefined) {
183
+ return formatMetadataValue(metadataValue, trimmedKey, metadata);
184
+ }
185
+ // Return original if no reference found
186
+ return match;
187
+ });
188
+ });
189
+ return processedLines.join('\n');
190
+ }
191
+ /**
192
+ * Gets a potentially nested value from an object using dot notation
143
193
  */
144
194
  function getNestedValue(obj, path) {
145
195
  const keys = path.split('.');
@@ -153,121 +203,28 @@ function getNestedValue(obj, path) {
153
203
  return value;
154
204
  }
155
205
  /**
156
- * Processes special reference formats like dates and currency amounts
157
- *
158
- * Applies appropriate formatting to reference values based on their type and
159
- * optional format specifiers. Handles dates, currency amounts, and falls back
160
- * to string conversion for other types.
161
- *
162
- * @param {any} value - The reference value to format
163
- * @param {string} [format] - Optional format specifier (e.g., "currency:USD:en-US")
164
- * @returns {string} Formatted value as string
165
- * @example
166
- * ```typescript
167
- * // Date formatting
168
- * const date = new Date("2024-03-15");
169
- * console.log(formatReferenceValue(date)); // "2024-03-15"
170
- * console.log(formatReferenceValue(date, "long")); // "March 15, 2024"
171
- * console.log(formatReferenceValue(date, "short")); // "3/15/2024"
172
- *
173
- * // Currency formatting
174
- * console.log(formatReferenceValue(1500, "currency:USD")); // "$1,500.00"
175
- * console.log(formatReferenceValue(1500, "currency:EUR:de-DE")); // "1.500,00 €"
176
- *
177
- * // Default string conversion
178
- * console.log(formatReferenceValue("Hello World")); // "Hello World"
179
- * console.log(formatReferenceValue(12345)); // "12345"
180
- * ```
206
+ * Formats metadata values based on type and context
181
207
  */
182
- function formatReferenceValue(value, format) {
183
- if (value === undefined || value === null) {
208
+ function formatMetadataValue(value, key, metadata) {
209
+ if (value === undefined) {
184
210
  return '';
185
211
  }
186
- // Handle different types
187
- if (typeof value === 'object' && value instanceof Date) {
188
- return formatDate(value, format);
212
+ if (value === null) {
213
+ return 'null';
189
214
  }
190
- if (typeof value === 'number' && format?.startsWith('currency')) {
191
- return formatCurrency(value, format);
215
+ // Handle Date objects
216
+ if (value instanceof Date) {
217
+ return value.toISOString().split('T')[0]; // ISO date format
192
218
  }
193
- // Default: convert to string
194
- return String(value);
195
- }
196
- /**
197
- * Formats a date value
198
- *
199
- * Converts a Date object to a formatted string using various format options.
200
- * Supports ISO format (default), short format, and long format for different
201
- * document presentation needs.
202
- *
203
- * @private
204
- * @param {Date} date - Date to format
205
- * @param {string} [format] - Date format specification ("short", "long", or default ISO)
206
- * @returns {string} Formatted date string
207
- * @example
208
- * ```typescript
209
- * const date = new Date("2024-03-15T10:30:00Z");
210
- *
211
- * console.log(formatDate(date)); // "2024-03-15" (ISO format)
212
- * console.log(formatDate(date, "short")); // "3/15/2024" (locale-specific)
213
- * console.log(formatDate(date, "long")); // "March 15, 2024" (long format)
214
- * ```
215
- */
216
- function formatDate(date, format) {
217
- if (!format) {
218
- // Default format: YYYY-MM-DD
219
- return date.toISOString().split('T')[0];
219
+ // Handle currency amounts
220
+ if (typeof value === 'number' && key.includes('amount')) {
221
+ const currency = metadata.payment_currency || 'USD';
222
+ return new Intl.NumberFormat('en-US', {
223
+ style: 'currency',
224
+ currency,
225
+ }).format(value);
220
226
  }
221
- // Custom date formatting
222
- if (format === 'short') {
223
- return date.toLocaleDateString();
224
- }
225
- else if (format === 'long') {
226
- return date.toLocaleDateString(undefined, {
227
- year: 'numeric',
228
- month: 'long',
229
- day: 'numeric',
230
- });
231
- }
232
- return date.toISOString().split('T')[0]; // Default to ISO format
233
- }
234
- /**
235
- * Formats a number as currency
236
- *
237
- * Converts a numeric amount to a formatted currency string using the
238
- * Intl.NumberFormat API. Supports different currencies and locales
239
- * based on the format specification.
240
- *
241
- * @private
242
- * @param {number} amount - Amount to format
243
- * @param {string} [format] - Currency format specification ("currency:CODE:locale")
244
- * @returns {string} Formatted currency string
245
- * @example
246
- * ```typescript
247
- * console.log(formatCurrency(1500)); // "$1,500.00" (default USD)
248
- * console.log(formatCurrency(1500, "currency:EUR")); // "€1,500.00"
249
- * console.log(formatCurrency(1500, "currency:GBP:en-GB")); // "£1,500.00"
250
- * console.log(formatCurrency(1500, "currency:JPY:ja-JP")); // "¥1,500"
251
- * console.log(formatCurrency(1500, "currency:EUR:de-DE")); // "1.500,00 €"
252
- * ```
253
- */
254
- function formatCurrency(amount, format) {
255
- let currency = 'USD';
256
- let locale = 'en-US';
257
- // Parse format specification
258
- if (format) {
259
- const parts = format.split(':');
260
- if (parts.length > 1) {
261
- currency = parts[1].trim().toUpperCase();
262
- }
263
- if (parts.length > 2) {
264
- locale = parts[2].trim();
265
- }
266
- }
267
- // Format using Intl.NumberFormat
268
- return new Intl.NumberFormat(locale, {
269
- style: 'currency',
270
- currency,
271
- }).format(amount);
227
+ // Default string conversion
228
+ return String(value);
272
229
  }
273
230
  //# sourceMappingURL=reference-processor.js.map