diff --git a/tests/corpus/11-marks.docx b/tests/corpus/11-marks.docx new file mode 100644 index 0000000..265caee Binary files /dev/null and b/tests/corpus/11-marks.docx differ diff --git a/tests/corpus/11-marks.odt b/tests/corpus/11-marks.odt new file mode 100644 index 0000000..949953d Binary files /dev/null and b/tests/corpus/11-marks.odt differ diff --git a/tests/corpus/12-notes.docx b/tests/corpus/12-notes.docx new file mode 100644 index 0000000..3ac463b Binary files /dev/null and b/tests/corpus/12-notes.docx differ diff --git a/tests/corpus/12-notes.odt b/tests/corpus/12-notes.odt new file mode 100644 index 0000000..b59106b Binary files /dev/null and b/tests/corpus/12-notes.odt differ diff --git a/tests/corpus/13-images.docx b/tests/corpus/13-images.docx new file mode 100644 index 0000000..bdcd54e Binary files /dev/null and b/tests/corpus/13-images.docx differ diff --git a/tests/corpus/13-images.odt b/tests/corpus/13-images.odt new file mode 100644 index 0000000..f6b0526 Binary files /dev/null and b/tests/corpus/13-images.odt differ diff --git a/tests/corpus/14-formulas.docx b/tests/corpus/14-formulas.docx new file mode 100644 index 0000000..0ee68ad Binary files /dev/null and b/tests/corpus/14-formulas.docx differ diff --git a/tests/corpus/14-formulas.odt b/tests/corpus/14-formulas.odt new file mode 100644 index 0000000..f8687a6 Binary files /dev/null and b/tests/corpus/14-formulas.odt differ diff --git a/tests/render-parity/make-fixtures.mjs b/tests/render-parity/make-fixtures.mjs index 5010eb5..9832b2b 100644 --- a/tests/render-parity/make-fixtures.mjs +++ b/tests/render-parity/make-fixtures.mjs @@ -11,11 +11,18 @@ import { Document, Packer, Paragraph, TextRun, HeadingLevel, AlignmentType, LevelFormat, Table, TableRow, TableCell, WidthType, convertMillimetersToTwip, Header, Footer, PageNumber, TabStopType, + FootnoteReferenceRun, ImageRun, ExternalHyperlink, UnderlineType, + Math as DocxMath, MathRun, MathFraction, MathNumerator, MathDenominator, MathRadical, } from 'docx'; const OUT = join(dirname(fileURLToPath(import.meta.url)), '..', 'corpus'); mkdirSync(OUT, { recursive: true }); +// An optional regex argument regenerates matching files only (and converts only +// their ODT twins), so extending the corpus leaves the committed rest untouched. +const only = process.argv[2] ? new RegExp(process.argv[2]) : null; +const written = []; + const LOREM = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.'; const page = { margin: { top: 1134, bottom: 1134, left: 1134, right: 1134 } }; // 2cm @@ -31,6 +38,7 @@ const heading = (id, name, halfPt, before, after, level) => ({ }); async function write(name, sections, defaultRun = { font: 'Times New Roman', size: 24 }, extra = {}) { + if (only && !only.test(name)) return; const doc = new Document({ styles: { default: { document: { run: defaultRun } }, @@ -45,6 +53,7 @@ async function write(name, sections, defaultRun = { font: 'Times New Roman', siz sections, }); writeFileSync(join(OUT, name), await Packer.toBuffer(doc)); + written.push(name); console.log('wrote', name); } @@ -197,10 +206,88 @@ await write('04-table.docx', [{ ], }]); +// 11. Run formatting beyond bold/italic, plus a link — the marks the import maps. +await write('11-marks.docx', [{ + properties: { page }, + children: [ + new Paragraph({ children: [ + new TextRun({ text: 'underlined ', underline: { type: UnderlineType.SINGLE } }), + new TextRun({ text: 'struck ', strike: true }), + new TextRun({ text: 'highlighted ', highlight: 'yellow' }), + new TextRun({ text: 'colored ', color: 'C00000' }), + new TextRun({ text: 'super', superScript: true }), + new TextRun({ text: ' and ' }), + new TextRun({ text: 'sub', subScript: true }), + ] }), + new Paragraph({ children: [ + new TextRun('A '), + new ExternalHyperlink({ link: 'https://example.org/', children: [ + new TextRun({ text: 'link to example.org', style: 'Hyperlink' }), + ] }), + new TextRun(' in running text.'), + ] }), + para(LOREM), + ], +}]); + +// 12. Footnotes: two anchors in flowing text, each with its own body. +await write('12-notes.docx', [{ + properties: { page }, + children: [ + new Paragraph({ children: [ + new TextRun('A claim'), new FootnoteReferenceRun(1), + new TextRun(' and another'), new FootnoteReferenceRun(2), + new TextRun(' in one paragraph.'), + ] }), + para(LOREM), + ], +}], undefined, { + footnotes: { + 1: { children: [para('The first footnote body.')] }, + 2: { children: [para('The second footnote body.')] }, + }, +}); + +// 13. Images: an inline picture in the line, sized in EMU by the lib. +const PNG = Buffer.from( + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==', + 'base64'); +await write('13-images.docx', [{ + properties: { page }, + children: [ + new Paragraph({ children: [ + new TextRun('Before '), + new ImageRun({ type: 'png', data: PNG, transformation: { width: 96, height: 48 } }), + new TextRun(' after.'), + ] }), + para(LOREM), + ], +}]); + +// 14. OMML formulas: one inline in the sentence, one alone on its line. +const frac = () => new MathFraction({ + numerator: [new MathNumerator([new MathRun('a')])], + denominator: [new MathDenominator([new MathRun('b')])], +}); +await write('14-formulas.docx', [{ + properties: { page }, + children: [ + new Paragraph({ children: [ + new TextRun('Inline '), + new DocxMath({ children: [frac()] }), + new TextRun(' in the sentence.'), + ] }), + new Paragraph({ children: [new DocxMath({ children: [ + new MathRadical({ children: [new MathRun('x')], degree: [] }), new MathRun('+1'), + ] })] }), + para(LOREM), + ], +}]); + // ODT twins, written by LibreOffice itself — the dominant ODT producer, so they carry // its own conventions (percentage font sizes, Text Body, list styles) and exercise the // foreign-document path our own exporter never produces. -const docxFiles = readdirSync(OUT).filter((f) => f.endsWith('.docx')); +const docxFiles = written; // Its own profile, in a temp dir: LibreOffice writes a whole user installation into // it, and this one's parent is committed. const profile = mkdtempSync(join(tmpdir(), 'corpus-lo-'));