officeparser 7.1.0 → 7.2.1

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.
Files changed (46) hide show
  1. package/README.md +152 -56
  2. package/dist/OfficeGenerator.d.ts +6 -2
  3. package/dist/OfficeGenerator.js +30 -9
  4. package/dist/OfficeParser.d.ts +1 -1
  5. package/dist/OfficeParser.js +1 -1
  6. package/dist/cli.d.ts +18 -12
  7. package/dist/cli.js +255 -81
  8. package/dist/defaults.js +12 -1
  9. package/dist/generators/BaseGenerator.d.ts +4 -3
  10. package/dist/generators/BaseGenerator.js +13 -1
  11. package/dist/generators/ChunkingGenerator.js +32 -5
  12. package/dist/generators/CsvGenerator.d.ts +1 -1
  13. package/dist/generators/HtmlGenerator.d.ts +2 -1
  14. package/dist/generators/HtmlGenerator.js +481 -42
  15. package/dist/generators/MarkdownGenerator.d.ts +1 -1
  16. package/dist/generators/MarkdownGenerator.js +35 -2
  17. package/dist/generators/PdfGenerator.d.ts +1 -1
  18. package/dist/generators/PdfGenerator.js +0 -6
  19. package/dist/generators/RtfGenerator.d.ts +2 -1
  20. package/dist/generators/RtfGenerator.js +49 -6
  21. package/dist/generators/TextGenerator.d.ts +1 -1
  22. package/dist/generators/TextGenerator.js +6 -0
  23. package/dist/officeparser.browser.d.ts +267 -54
  24. package/dist/officeparser.browser.iife.js +599 -187
  25. package/dist/officeparser.browser.mjs +599 -187
  26. package/dist/parsers/CsvParser.js +1 -1
  27. package/dist/parsers/ExcelParser.js +63 -19
  28. package/dist/parsers/HtmlParser.js +10 -1
  29. package/dist/parsers/MarkdownParser.js +13 -10
  30. package/dist/parsers/OpenOfficeParser.js +57 -34
  31. package/dist/parsers/PdfParser.js +28 -3
  32. package/dist/parsers/PowerPointParser.js +164 -40
  33. package/dist/parsers/RtfParser.js +28 -24
  34. package/dist/parsers/WordParser.js +154 -11
  35. package/dist/sbom.cdx.json +100 -100
  36. package/dist/types.d.ts +268 -53
  37. package/dist/types.js +4 -0
  38. package/dist/utils/astUtils.d.ts +2 -2
  39. package/dist/utils/astUtils.js +2 -1
  40. package/dist/utils/configUtils.d.ts +5 -0
  41. package/dist/utils/configUtils.js +55 -1
  42. package/dist/utils/errorUtils.js +3 -1
  43. package/dist/utils/moduleLoader.js +55 -11
  44. package/dist/utils/xmlUtils.d.ts +9 -0
  45. package/dist/utils/xmlUtils.js +53 -1
  46. package/package.json +6 -3
@@ -37,7 +37,7 @@ export declare class MarkdownGenerator extends BaseGenerator<'md'> {
37
37
  *
38
38
  * @returns A Markdown string
39
39
  */
40
- generate(): Promise<ConversionResult>;
40
+ generate(): Promise<ConversionResult<'md'>>;
41
41
  /**
42
42
  * Recursively processes nodes and builds output.
43
43
  * Overridden to provide AST optimization (merging adjacent text nodes).
@@ -136,7 +136,9 @@ class MarkdownGenerator extends BaseGenerator_js_1.BaseGenerator {
136
136
  else if (this.config.generateIds) {
137
137
  id = ` {#${this.slugify(this.getNodeText(node))}}`;
138
138
  }
139
- const anchors = remainingAnchors.map(aid => `<a name="${aid}"></a>`).join('');
139
+ const anchors = this.config.mdConfig.fallbackToHtml
140
+ ? remainingAnchors.map(aid => `<a name="${aid}"></a>`).join('')
141
+ : '';
140
142
  let content = `${prefix}${childrenOutput}${id}`;
141
143
  // Alignment fallback via HTML div/p
142
144
  if (this.config.mdConfig.fallbackToHtml && meta?.alignment && meta.alignment !== 'left') {
@@ -216,6 +218,11 @@ class MarkdownGenerator extends BaseGenerator_js_1.BaseGenerator {
216
218
  const anchors = this.renderAnchors(node.metadata);
217
219
  return `\n---\n\n${anchors}${anchors ? '\n' : ''}${childrenOutput}\n\n`;
218
220
  }
221
+ case 'note': {
222
+ const meta = node.metadata;
223
+ const typeLabel = meta?.noteType === 'footnote' ? 'Footnote' : (meta?.noteType === 'endnote' ? 'Endnote' : 'Note');
224
+ return `> **${typeLabel}:** ${childrenOutput.trim()}\n\n`;
225
+ }
219
226
  default:
220
227
  return childrenOutput;
221
228
  }
@@ -239,6 +246,13 @@ class MarkdownGenerator extends BaseGenerator_js_1.BaseGenerator {
239
246
  }
240
247
  output += result;
241
248
  }
249
+ if (this.collectedNotes.length > 0) {
250
+ let notesMd = '\n\n---\n\n### Notes\n\n';
251
+ for (const note of this.collectedNotes) {
252
+ notesMd += await this.processNodeRecursive(note, processor);
253
+ }
254
+ output += notesMd;
255
+ }
242
256
  return {
243
257
  value: (output + '\n\n' + this.hoistedContent.join('\n\n')).trim(),
244
258
  messages: this.messages
@@ -265,7 +279,18 @@ class MarkdownGenerator extends BaseGenerator_js_1.BaseGenerator {
265
279
  childrenOutput += await this.processNodeRecursive(child, processor);
266
280
  }
267
281
  }
268
- return await processor(node, childrenOutput);
282
+ if (node.notes && node.notes.length > 0) {
283
+ if (node.type !== 'slide') {
284
+ this.collectedNotes.push(...node.notes);
285
+ }
286
+ }
287
+ let result = await processor(node, childrenOutput);
288
+ if (node.type === 'slide' && node.notes && node.notes.length > 0) {
289
+ for (const note of node.notes) {
290
+ result += await this.processNodeRecursive(note, processor);
291
+ }
292
+ }
293
+ return result;
269
294
  }
270
295
  /**
271
296
  * Merges adjacent text nodes with identical formatting and metadata.
@@ -282,9 +307,17 @@ class MarkdownGenerator extends BaseGenerator_js_1.BaseGenerator {
282
307
  current.text = (current.text || '') + (node.text || '');
283
308
  if (current.rawContent && node.rawContent)
284
309
  current.rawContent += node.rawContent;
310
+ if (node.notes && node.notes.length > 0) {
311
+ if (!current.notes)
312
+ current.notes = [];
313
+ current.notes.push(...node.notes);
314
+ }
285
315
  }
286
316
  else {
287
317
  current = { ...node }; // Clone
318
+ if (node.notes) {
319
+ current.notes = [...node.notes];
320
+ }
288
321
  result.push(current);
289
322
  }
290
323
  }
@@ -9,7 +9,7 @@ import { BaseGenerator } from './BaseGenerator.js';
9
9
  */
10
10
  export declare class PdfGenerator extends BaseGenerator<'pdf'> {
11
11
  constructor(ast: OfficeParserAST, config?: GeneratorConfig<'pdf'>);
12
- generate(): Promise<ConversionResult>;
12
+ generate(): Promise<ConversionResult<'pdf'>>;
13
13
  /**
14
14
  * Node.js implementation using Puppeteer.
15
15
  * Uses dynamic import to avoid bundling puppeteer into the library core.
@@ -23,12 +23,6 @@ class PdfGenerator extends BaseGenerator_js_1.BaseGenerator {
23
23
  const htmlGenerator = new HtmlGenerator_js_1.HtmlGenerator(this.ast, {
24
24
  ...this.config,
25
25
  htmlConfig: { ...this.config.htmlConfig, standalone: true },
26
- mdConfig: undefined,
27
- chunksConfig: undefined,
28
- csvConfig: undefined,
29
- textConfig: undefined,
30
- pdfConfig: undefined,
31
- rtfConfig: undefined,
32
26
  });
33
27
  const htmlResult = await htmlGenerator.generate();
34
28
  const html = typeof htmlResult.value === 'string' ? htmlResult.value : '';
@@ -7,9 +7,10 @@ export declare class RtfGenerator extends BaseGenerator<'rtf'> {
7
7
  private colorTable;
8
8
  private inTable;
9
9
  constructor(ast: OfficeParserAST, config?: GeneratorConfig<'rtf'>);
10
- generate(): Promise<ConversionResult>;
10
+ generate(): Promise<ConversionResult<'rtf'>>;
11
11
  protected processNodeRecursive(node: OfficeContentNode, processor: (node: OfficeContentNode, childrenOutput: string) => Promise<string>): Promise<string>;
12
12
  private renderBody;
13
13
  private getColorIndex;
14
+ private isLightColor;
14
15
  private escapeRtf;
15
16
  }
@@ -15,7 +15,7 @@ class RtfGenerator extends BaseGenerator_js_1.BaseGenerator {
15
15
  this.colorTable = [];
16
16
  // We first process all nodes to collect colors and analyze structure
17
17
  const bodyContent = await this.renderBody(this.ast);
18
- let output = '{\\rtf1\\ansi\\deff0\n';
18
+ let output = '{\\rtf1\\ansi\\uc1\\deff0\n';
19
19
  // 1. Info Group (Metadata)
20
20
  if (this.config.renderMetadata && this.ast.metadata) {
21
21
  output += '{\\info';
@@ -100,16 +100,34 @@ class RtfGenerator extends BaseGenerator_js_1.BaseGenerator {
100
100
  suffix = '\\strike0 ' + suffix;
101
101
  }
102
102
  if (f.color) {
103
- const idx = this.getColorIndex(f.color);
104
- prefix += `\\cf${idx + 1} `;
103
+ // RTF default background is white. Ensure light text without a dark background remains readable.
104
+ const isTextLight = this.isLightColor(f.color);
105
+ const isBgLight = !f.backgroundColor || this.isLightColor(f.backgroundColor);
106
+ if (!(isTextLight && isBgLight)) {
107
+ const idx = this.getColorIndex(f.color);
108
+ prefix += `\\cf${idx + 1} `;
109
+ }
105
110
  }
106
111
  if (f.backgroundColor) {
107
112
  const idx = this.getColorIndex(f.backgroundColor);
108
113
  prefix += `\\highlight${idx + 1} `;
109
114
  }
110
115
  if (f.size) {
111
- const pt = parseInt(f.size);
112
- prefix += `\\fs${pt * 2} `;
116
+ let pt = 12; // default
117
+ const val = parseFloat(f.size);
118
+ if (!isNaN(val)) {
119
+ if (f.size.includes('in'))
120
+ pt = val * 72;
121
+ else if (f.size.includes('cm'))
122
+ pt = val * 28.3465;
123
+ else if (f.size.includes('mm'))
124
+ pt = val * 2.83465;
125
+ else if (f.size.includes('px'))
126
+ pt = val * 0.75;
127
+ else
128
+ pt = val;
129
+ }
130
+ prefix += `\\fs${Math.round(pt * 2)} `;
113
131
  }
114
132
  text = `{\\f0 ${prefix}${text}${suffix}}`;
115
133
  }
@@ -203,6 +221,12 @@ class RtfGenerator extends BaseGenerator_js_1.BaseGenerator {
203
221
  for (const node of ast.content) {
204
222
  body += await this.processNodeRecursive(node, processor);
205
223
  }
224
+ if (this.collectedNotes.length > 0) {
225
+ body += '\\pard\\sb120\\sa120\\keepn{\\b Notes:}\\par\n';
226
+ for (const note of this.collectedNotes) {
227
+ body += await this.processNodeRecursive(note, processor);
228
+ }
229
+ }
206
230
  return body;
207
231
  }
208
232
  getColorIndex(hex) {
@@ -214,13 +238,32 @@ class RtfGenerator extends BaseGenerator_js_1.BaseGenerator {
214
238
  }
215
239
  return idx;
216
240
  }
241
+ isLightColor(hex) {
242
+ if (!hex || hex.length !== 7 || !hex.startsWith('#'))
243
+ return false;
244
+ const r = parseInt(hex.substring(1, 3), 16);
245
+ const g = parseInt(hex.substring(3, 5), 16);
246
+ const b = parseInt(hex.substring(5, 7), 16);
247
+ if (isNaN(r) || isNaN(g) || isNaN(b))
248
+ return false;
249
+ // Simple luminance calculation
250
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
251
+ return luminance > 0.8;
252
+ }
217
253
  escapeRtf(text) {
218
254
  return text
219
255
  .replace(/\\/g, '\\\\')
220
256
  .replace(/{/g, '\\{')
221
257
  .replace(/}/g, '\\}')
222
258
  .replace(/[^\x00-\x7F]/g, (match) => {
223
- return `\\u${match.charCodeAt(0)}?`;
259
+ let code = match.charCodeAt(0);
260
+ if (code < 256) {
261
+ return `\\'${code.toString(16).padStart(2, '0')}`;
262
+ }
263
+ if (code > 32767) {
264
+ code -= 65536;
265
+ }
266
+ return `{\\uc0\\u${code}}`;
224
267
  });
225
268
  }
226
269
  }
@@ -8,6 +8,6 @@ export declare class TextGenerator extends BaseGenerator<'text'> {
8
8
  /**
9
9
  * Generates plain text by concatenating text content from nodes.
10
10
  */
11
- generate(): Promise<ConversionResult>;
11
+ generate(): Promise<ConversionResult<'text'>>;
12
12
  private renderTable;
13
13
  }
@@ -62,6 +62,12 @@ class TextGenerator extends BaseGenerator_js_1.BaseGenerator {
62
62
  for (const node of this.ast.content) {
63
63
  output += await this.processNodeRecursive(node, processor);
64
64
  }
65
+ if (this.collectedNotes.length > 0) {
66
+ output += `${newline}${newline}--- Notes ---${newline}`;
67
+ for (const note of this.collectedNotes) {
68
+ output += await this.processNodeRecursive(note, processor);
69
+ }
70
+ }
65
71
  return {
66
72
  value: output.trim(),
67
73
  messages: this.messages