postext-pdf 0.1.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/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/__bench__/render.bench.test.d.ts +2 -0
- package/dist/__bench__/render.bench.test.d.ts.map +1 -0
- package/dist/__bench__/render.bench.test.js +86 -0
- package/dist/__bench__/render.bench.test.js.map +1 -0
- package/dist/__tests__/accessibility.test.d.ts +2 -0
- package/dist/__tests__/accessibility.test.d.ts.map +1 -0
- package/dist/__tests__/accessibility.test.js +364 -0
- package/dist/__tests__/accessibility.test.js.map +1 -0
- package/dist/__tests__/contentsLinks.test.d.ts +2 -0
- package/dist/__tests__/contentsLinks.test.d.ts.map +1 -0
- package/dist/__tests__/contentsLinks.test.js +131 -0
- package/dist/__tests__/contentsLinks.test.js.map +1 -0
- package/dist/__tests__/fontCache.test.d.ts +2 -0
- package/dist/__tests__/fontCache.test.d.ts.map +1 -0
- package/dist/__tests__/fontCache.test.js +42 -0
- package/dist/__tests__/fontCache.test.js.map +1 -0
- package/dist/__tests__/headerFooter.test.d.ts +2 -0
- package/dist/__tests__/headerFooter.test.d.ts.map +1 -0
- package/dist/__tests__/headerFooter.test.js +68 -0
- package/dist/__tests__/headerFooter.test.js.map +1 -0
- package/dist/__tests__/rotatedTable.test.d.ts +2 -0
- package/dist/__tests__/rotatedTable.test.d.ts.map +1 -0
- package/dist/__tests__/rotatedTable.test.js +112 -0
- package/dist/__tests__/rotatedTable.test.js.map +1 -0
- package/dist/__tests__/svgVector.test.d.ts +2 -0
- package/dist/__tests__/svgVector.test.d.ts.map +1 -0
- package/dist/__tests__/svgVector.test.js +322 -0
- package/dist/__tests__/svgVector.test.js.map +1 -0
- package/dist/__tests__/toUnicode.test.d.ts +2 -0
- package/dist/__tests__/toUnicode.test.d.ts.map +1 -0
- package/dist/__tests__/toUnicode.test.js +57 -0
- package/dist/__tests__/toUnicode.test.js.map +1 -0
- package/dist/colors.d.ts +23 -0
- package/dist/colors.d.ts.map +1 -0
- package/dist/colors.js +47 -0
- package/dist/colors.js.map +1 -0
- package/dist/fontCache.d.ts +41 -0
- package/dist/fontCache.d.ts.map +1 -0
- package/dist/fontCache.js +154 -0
- package/dist/fontCache.js.map +1 -0
- package/dist/fontString.d.ts +14 -0
- package/dist/fontString.d.ts.map +1 -0
- package/dist/fontString.js +43 -0
- package/dist/fontString.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/pdf-backend/blockRender.d.ts +15 -0
- package/dist/pdf-backend/blockRender.d.ts.map +1 -0
- package/dist/pdf-backend/blockRender.js +244 -0
- package/dist/pdf-backend/blockRender.js.map +1 -0
- package/dist/pdf-backend/fontHelpers.d.ts +6 -0
- package/dist/pdf-backend/fontHelpers.d.ts.map +1 -0
- package/dist/pdf-backend/fontHelpers.js +81 -0
- package/dist/pdf-backend/fontHelpers.js.map +1 -0
- package/dist/pdf-backend/headerFooter.d.ts +15 -0
- package/dist/pdf-backend/headerFooter.d.ts.map +1 -0
- package/dist/pdf-backend/headerFooter.js +145 -0
- package/dist/pdf-backend/headerFooter.js.map +1 -0
- package/dist/pdf-backend/index.d.ts +47 -0
- package/dist/pdf-backend/index.d.ts.map +1 -0
- package/dist/pdf-backend/index.js +227 -0
- package/dist/pdf-backend/index.js.map +1 -0
- package/dist/pdf-backend/links.d.ts +44 -0
- package/dist/pdf-backend/links.d.ts.map +1 -0
- package/dist/pdf-backend/links.js +110 -0
- package/dist/pdf-backend/links.js.map +1 -0
- package/dist/pdf-backend/outlines.d.ts +8 -0
- package/dist/pdf-backend/outlines.d.ts.map +1 -0
- package/dist/pdf-backend/outlines.js +145 -0
- package/dist/pdf-backend/outlines.js.map +1 -0
- package/dist/pdf-backend/pageDecorations.d.ts +13 -0
- package/dist/pdf-backend/pageDecorations.d.ts.map +1 -0
- package/dist/pdf-backend/pageDecorations.js +88 -0
- package/dist/pdf-backend/pageDecorations.js.map +1 -0
- package/dist/pdf-backend/pageLabels.d.ts +8 -0
- package/dist/pdf-backend/pageLabels.d.ts.map +1 -0
- package/dist/pdf-backend/pageLabels.js +61 -0
- package/dist/pdf-backend/pageLabels.js.map +1 -0
- package/dist/pdf-backend/primitives.d.ts +46 -0
- package/dist/pdf-backend/primitives.d.ts.map +1 -0
- package/dist/pdf-backend/primitives.js +162 -0
- package/dist/pdf-backend/primitives.js.map +1 -0
- package/dist/pdf-backend/renderResourceBlock.d.ts +87 -0
- package/dist/pdf-backend/renderResourceBlock.d.ts.map +1 -0
- package/dist/pdf-backend/renderResourceBlock.js +753 -0
- package/dist/pdf-backend/renderResourceBlock.js.map +1 -0
- package/dist/pdf-backend/structureFlow.d.ts +55 -0
- package/dist/pdf-backend/structureFlow.d.ts.map +1 -0
- package/dist/pdf-backend/structureFlow.js +180 -0
- package/dist/pdf-backend/structureFlow.js.map +1 -0
- package/dist/pdf-backend/svgVector.d.ts +144 -0
- package/dist/pdf-backend/svgVector.d.ts.map +1 -0
- package/dist/pdf-backend/svgVector.js +1455 -0
- package/dist/pdf-backend/svgVector.js.map +1 -0
- package/dist/pdf-backend/tagging.d.ts +136 -0
- package/dist/pdf-backend/tagging.d.ts.map +1 -0
- package/dist/pdf-backend/tagging.js +296 -0
- package/dist/pdf-backend/tagging.js.map +1 -0
- package/dist/woff2.d.ts +11 -0
- package/dist/woff2.d.ts.map +1 -0
- package/dist/woff2.js +47 -0
- package/dist/woff2.js.map +1 -0
- package/dist/worker/client.d.ts +30 -0
- package/dist/worker/client.d.ts.map +1 -0
- package/dist/worker/client.js +112 -0
- package/dist/worker/client.js.map +1 -0
- package/dist/worker/pdf.worker.d.ts +2 -0
- package/dist/worker/pdf.worker.d.ts.map +1 -0
- package/dist/worker/pdf.worker.js +67 -0
- package/dist/worker/pdf.worker.js.map +1 -0
- package/dist/worker/protocol.d.ts +49 -0
- package/dist/worker/protocol.d.ts.map +1 -0
- package/dist/worker/protocol.js +2 -0
- package/dist/worker/protocol.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll } from 'vitest';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { PDFArray, PDFDict, PDFDocument, PDFHexString, PDFName, PDFNumber, PDFRef, PDFString } from 'pdf-lib';
|
|
4
|
+
import fontkit from '@pdf-lib/fontkit';
|
|
5
|
+
import { buildDocument, computeOutlineFor, parseMarkdown } from 'postext';
|
|
6
|
+
import { renderToPdf } from '../pdf-backend';
|
|
7
|
+
import { parseFontString } from '../fontString';
|
|
8
|
+
const fontBytes = fs.readFileSync(new URL('../../../../apps/web/public/fonts/Lora-Regular.ttf', import.meta.url));
|
|
9
|
+
const fontProvider = async () => new Uint8Array(fontBytes);
|
|
10
|
+
const face = fontkit.create(fontBytes);
|
|
11
|
+
class StubCtx {
|
|
12
|
+
font = '';
|
|
13
|
+
measureText(s) {
|
|
14
|
+
const sizePx = parseFontString(this.font)?.sizePx ?? 16;
|
|
15
|
+
const run = face.layout(s);
|
|
16
|
+
return { width: (run.advanceWidth / face.unitsPerEm) * sizePx };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
globalThis.OffscreenCanvas = class {
|
|
20
|
+
getContext() {
|
|
21
|
+
return new StubCtx();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const pt = (value) => ({ value, unit: 'pt' });
|
|
25
|
+
const filler = (n) => Array.from({ length: n }, (_, i) => `Paragraph ${i} with enough words to consume vertical space and force the page to overflow.`).join('\n\n');
|
|
26
|
+
const config = {
|
|
27
|
+
page: {
|
|
28
|
+
width: pt(360), height: pt(300),
|
|
29
|
+
margins: { top: pt(18), bottom: pt(18), left: pt(18), right: pt(18) },
|
|
30
|
+
pageNumbering: { format: 'lower-roman', startAt: 1 },
|
|
31
|
+
},
|
|
32
|
+
layout: { layoutType: 'single' },
|
|
33
|
+
locale: 'en-us',
|
|
34
|
+
headings: { levels: [{ level: 1, breakBefore: { enabled: true, parity: 'odd' } }] },
|
|
35
|
+
headingStyles: [{ id: 'front', numbered: false }],
|
|
36
|
+
toc: { subtitle: { enabled: true, attr: 'author' }, parts: { enabled: true } },
|
|
37
|
+
};
|
|
38
|
+
const book = `# Contents {style="front" toc="false"}
|
|
39
|
+
|
|
40
|
+
:::toc
|
|
41
|
+
|
|
42
|
+
# Preface {style="front"}
|
|
43
|
+
|
|
44
|
+
${filler(2)}
|
|
45
|
+
|
|
46
|
+
:::numbering{format="decimal" startAt=1}
|
|
47
|
+
|
|
48
|
+
:::part{number="I" title="Foundations"}
|
|
49
|
+
:::
|
|
50
|
+
|
|
51
|
+
# The lantern {author="A. Author"}
|
|
52
|
+
|
|
53
|
+
${filler(3)}
|
|
54
|
+
|
|
55
|
+
# Trimming {author="B. Author"}
|
|
56
|
+
|
|
57
|
+
${filler(1)}`;
|
|
58
|
+
const textOf = (v) => (v instanceof PDFHexString || v instanceof PDFString ? v.decodeText() : undefined);
|
|
59
|
+
let pdf;
|
|
60
|
+
let doc;
|
|
61
|
+
beforeAll(async () => {
|
|
62
|
+
doc = buildDocument({ markdown: book, metadata: { title: 'Linked book' } }, config);
|
|
63
|
+
const bytes = await renderToPdf(doc, { fontProvider });
|
|
64
|
+
const out = process.env.POSTEXT_TOC_PDF_OUT;
|
|
65
|
+
if (out)
|
|
66
|
+
fs.writeFileSync(out, bytes);
|
|
67
|
+
pdf = await PDFDocument.load(bytes);
|
|
68
|
+
}, 60_000);
|
|
69
|
+
describe('contents rows as links', () => {
|
|
70
|
+
it('links every row to the top of the page it lists', () => {
|
|
71
|
+
const rows = doc.blocks.filter((b) => (b.tocEntry ?? b.tocPart) && b.pageIndex === 0);
|
|
72
|
+
expect(rows.length).toBe(4); // Preface, part I, The lantern, Trimming
|
|
73
|
+
const annots = pdf.getPage(0).node.Annots().asArray().map((r) => pdf.context.lookup(r, PDFDict));
|
|
74
|
+
expect(annots).toHaveLength(4);
|
|
75
|
+
const pages = pdf.getPages();
|
|
76
|
+
// Rows by the text the annotation describes (a part row is drawn after
|
|
77
|
+
// the column's other blocks, so annotation order is not row order).
|
|
78
|
+
const rowText = (b) => (b.tocPart ? `${b.tocPart.number} ${b.tocPart.title}` : b.lines.map((l) => l.text).join(' '));
|
|
79
|
+
const seen = new Set();
|
|
80
|
+
for (const annot of annots) {
|
|
81
|
+
expect(annot.get(PDFName.of('Subtype'))).toEqual(PDFName.of('Link'));
|
|
82
|
+
const contents = textOf(annot.get(PDFName.of('Contents')));
|
|
83
|
+
const row = rows.find((b) => rowText(b) === contents);
|
|
84
|
+
expect(row).toBeDefined();
|
|
85
|
+
seen.add(contents);
|
|
86
|
+
const target = pages[row.tocEntry?.pageIndex ?? row.tocPart.pageIndex];
|
|
87
|
+
const dest = annot.lookup(PDFName.of('Dest'), PDFArray).asArray();
|
|
88
|
+
expect(dest[0]).toEqual(target.ref);
|
|
89
|
+
expect(dest[1]).toEqual(PDFName.of('XYZ'));
|
|
90
|
+
expect(dest[3].asNumber()).toBeCloseTo(target.getHeight(), 3);
|
|
91
|
+
// Tagged: the annotation joins a `Link` element and describes its target.
|
|
92
|
+
expect(annot.get(PDFName.of('StructParent'))).toBeInstanceOf(PDFNumber);
|
|
93
|
+
}
|
|
94
|
+
expect(seen.has('I Foundations')).toBe(true);
|
|
95
|
+
expect([...seen].some((t) => t.startsWith('The lantern'))).toBe(true);
|
|
96
|
+
});
|
|
97
|
+
it('wraps each row\'s text in a Link structure element with its annotation', () => {
|
|
98
|
+
const root = pdf.catalog.lookup(PDFName.of('StructTreeRoot'), PDFDict);
|
|
99
|
+
const links = [];
|
|
100
|
+
const visit = (ref) => {
|
|
101
|
+
const dict = ref instanceof PDFRef ? pdf.context.lookup(ref, PDFDict) : ref;
|
|
102
|
+
if (dict.get(PDFName.of('S')) === PDFName.of('Link'))
|
|
103
|
+
links.push(dict);
|
|
104
|
+
const k = dict.get(PDFName.of('K'));
|
|
105
|
+
const kids = k instanceof PDFArray ? k.asArray() : k ? [k] : [];
|
|
106
|
+
for (const kid of kids) {
|
|
107
|
+
if (kid instanceof PDFRef)
|
|
108
|
+
visit(kid);
|
|
109
|
+
else if (kid instanceof PDFDict && kid.get(PDFName.of('S')))
|
|
110
|
+
visit(kid);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
visit(root);
|
|
114
|
+
expect(links).toHaveLength(4);
|
|
115
|
+
for (const link of links) {
|
|
116
|
+
const k = link.lookup(PDFName.of('K'), PDFArray).asArray().map((x) => (x instanceof PDFRef ? pdf.context.lookup(x) : x));
|
|
117
|
+
const types = k.map((x) => (x instanceof PDFDict ? textOf(x.get(PDFName.of('Type'))) ?? x.get(PDFName.of('Type'))?.decodeText() : 'mcid'));
|
|
118
|
+
expect(types.filter((t) => t === 'OBJR')).toHaveLength(1);
|
|
119
|
+
expect(types.filter((t) => t === 'MCR' || t === 'mcid').length).toBeGreaterThan(0);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
it('skips rows whose page lies outside a chapter rendered on its own', async () => {
|
|
123
|
+
// The chapter with the contents, laid out after ten pages of another
|
|
124
|
+
// chapter, listing a host outline that points into the book.
|
|
125
|
+
const outline = computeOutlineFor(parseMarkdown(book), config).map((e, i) => ({ ...e, pageLabel: String(i + 1), pageIndex: 100 + i }));
|
|
126
|
+
const alone = buildDocument({ markdown: book, outline, continuation: { pageIndexOffset: 10 } }, config);
|
|
127
|
+
const out = await PDFDocument.load(await renderToPdf(alone, { fontProvider }));
|
|
128
|
+
expect(out.getPage(0).node.Annots()?.asArray() ?? []).toHaveLength(0);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=contentsLinks.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contentsLinks.test.js","sourceRoot":"","sources":["../../src/__tests__/contentsLinks.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fontCache.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fontCache.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { PDFDocument } from 'pdf-lib';
|
|
4
|
+
import fontkit from '@pdf-lib/fontkit';
|
|
5
|
+
import { coverAllGlyphWidths } from '../fontCache';
|
|
6
|
+
// A TrueType face from the demo app's static fonts (OFL). The width fix is
|
|
7
|
+
// applied to CFF faces in production, but the mechanics are format-agnostic.
|
|
8
|
+
const FONT_PATH = new URL('../../../../apps/web/public/fonts/Fraunces-Regular.ttf', import.meta.url);
|
|
9
|
+
/** The `/W` array of the first CID font in `bytes`, as numbers. */
|
|
10
|
+
function widthsArray(bytes) {
|
|
11
|
+
const text = new TextDecoder('latin1').decode(bytes);
|
|
12
|
+
const match = /\/W \[([\s\S]*?)\]\s*\]/.exec(text);
|
|
13
|
+
if (!match)
|
|
14
|
+
return [];
|
|
15
|
+
return (match[1] + ']').replace(/[[\]]/g, ' ').trim().split(/\s+/).map(Number);
|
|
16
|
+
}
|
|
17
|
+
describe('coverAllGlyphWidths', () => {
|
|
18
|
+
it('lists an advance for every glyph in the face, not only the cmap-reachable ones', async () => {
|
|
19
|
+
const bytes = readFileSync(FONT_PATH);
|
|
20
|
+
const face = fontkit.create(bytes);
|
|
21
|
+
const plainDoc = await PDFDocument.create();
|
|
22
|
+
plainDoc.registerFontkit(fontkit);
|
|
23
|
+
const plain = await plainDoc.embedFont(bytes, { subset: false });
|
|
24
|
+
plainDoc.addPage().drawText('fi fl', { font: plain, size: 12 });
|
|
25
|
+
const plainWidths = widthsArray(await plainDoc.save({ useObjectStreams: false }));
|
|
26
|
+
const fixedDoc = await PDFDocument.create();
|
|
27
|
+
fixedDoc.registerFontkit(fontkit);
|
|
28
|
+
const fixed = await fixedDoc.embedFont(bytes, { subset: false });
|
|
29
|
+
coverAllGlyphWidths(fixed);
|
|
30
|
+
fixedDoc.addPage().drawText('fi fl', { font: fixed, size: 12 });
|
|
31
|
+
const fixedWidths = widthsArray(await fixedDoc.save({ useObjectStreams: false }));
|
|
32
|
+
// `[0 [w0 w1 … w(n-1)]]`: the leading CID plus one width per glyph.
|
|
33
|
+
expect(fixedWidths[0]).toBe(0);
|
|
34
|
+
expect(fixedWidths.length).toBe(face.numGlyphs + 1);
|
|
35
|
+
// pdf-lib's own table stops at the glyphs the cmap can reach.
|
|
36
|
+
expect(plainWidths.length).toBeLessThan(fixedWidths.length);
|
|
37
|
+
// Widths are in 1000-unit glyph space.
|
|
38
|
+
const space = face.glyphForCodePoint(0x20);
|
|
39
|
+
expect(fixedWidths[1 + space.id]).toBeCloseTo(space.advanceWidth * 1000 / face.unitsPerEm, 6);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
//# sourceMappingURL=fontCache.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fontCache.test.js","sourceRoot":"","sources":["../../src/__tests__/fontCache.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headerFooter.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/headerFooter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { PDFDocument } from 'pdf-lib';
|
|
3
|
+
import { FontCache } from '../fontCache';
|
|
4
|
+
import { renderHeaderFooterSlot } from '../pdf-backend/headerFooter';
|
|
5
|
+
import { makeScale } from '../pdf-backend/primitives';
|
|
6
|
+
/** The page's content stream operators, before pdf-lib deflates them. */
|
|
7
|
+
function pageContent(page) {
|
|
8
|
+
const stream = page.getContentStream();
|
|
9
|
+
return new TextDecoder('latin1').decode(stream.getUnencodedContents());
|
|
10
|
+
}
|
|
11
|
+
describe('design boxes in the PDF backend', () => {
|
|
12
|
+
it('draws a rounded box at its page position (path anchored at the page top, y down)', async () => {
|
|
13
|
+
const pdfDoc = await PDFDocument.create();
|
|
14
|
+
const page = pdfDoc.addPage([612, 792]);
|
|
15
|
+
// 72 dpi: 1 px = 1 pt, so the numbers below read directly as points.
|
|
16
|
+
const ctx = { page, pageHeightPt: 792, scale: makeScale(72), colorSpace: 'rgb' };
|
|
17
|
+
const slot = {
|
|
18
|
+
blocks: [{
|
|
19
|
+
kind: 'box',
|
|
20
|
+
id: 'dot',
|
|
21
|
+
bbox: { x: 72, y: 144, width: 36, height: 36 },
|
|
22
|
+
box: {
|
|
23
|
+
backgroundColor: '#9bcdbf',
|
|
24
|
+
borderWidthPx: 0,
|
|
25
|
+
borderRadiusPx: 18,
|
|
26
|
+
padding: { top: 0, right: 0, bottom: 0, left: 0 },
|
|
27
|
+
},
|
|
28
|
+
}],
|
|
29
|
+
};
|
|
30
|
+
const fontCache = new FontCache(pdfDoc, async () => new Uint8Array());
|
|
31
|
+
renderHeaderFooterSlot(ctx, slot, fontCache);
|
|
32
|
+
const content = pageContent(page);
|
|
33
|
+
// pdf-lib's drawSvgPath translates to the given origin then flips y, so
|
|
34
|
+
// the path must be anchored at the top-left of the page…
|
|
35
|
+
expect(content).toContain('1 0 0 1 0 792 cm');
|
|
36
|
+
expect(content).toContain('1 0 0 -1 0 0 cm');
|
|
37
|
+
// …and start at the box's top edge in top-down points (x + r, y).
|
|
38
|
+
expect(content).toMatch(/(^|\n)90 144 m\n/);
|
|
39
|
+
// The old absolute-coordinate path (bottom edge at 792 - 180 = 612)
|
|
40
|
+
// was mirrored below the page and never painted.
|
|
41
|
+
expect(content).not.toMatch(/(^|\n)90 612 m\n/);
|
|
42
|
+
});
|
|
43
|
+
it('draws a square box with drawRectangle at its page position', async () => {
|
|
44
|
+
const pdfDoc = await PDFDocument.create();
|
|
45
|
+
const page = pdfDoc.addPage([612, 792]);
|
|
46
|
+
const ctx = { page, pageHeightPt: 792, scale: makeScale(72), colorSpace: 'rgb' };
|
|
47
|
+
const slot = {
|
|
48
|
+
blocks: [{
|
|
49
|
+
kind: 'box',
|
|
50
|
+
id: 'tab',
|
|
51
|
+
bbox: { x: 0, y: 0, width: 50, height: 20 },
|
|
52
|
+
box: {
|
|
53
|
+
backgroundColor: '#9bcdbf',
|
|
54
|
+
borderWidthPx: 0,
|
|
55
|
+
borderRadiusPx: 0,
|
|
56
|
+
padding: { top: 0, right: 0, bottom: 0, left: 0 },
|
|
57
|
+
},
|
|
58
|
+
}],
|
|
59
|
+
};
|
|
60
|
+
renderHeaderFooterSlot(ctx, slot, new FontCache(pdfDoc, async () => new Uint8Array()));
|
|
61
|
+
const content = pageContent(page);
|
|
62
|
+
// pdf-lib translates to the bottom-left corner (y = 792 - 20) and
|
|
63
|
+
// traces the rectangle from the origin.
|
|
64
|
+
expect(content).toContain('1 0 0 1 0 772 cm');
|
|
65
|
+
expect(content).toContain('50 20 l');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=headerFooter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headerFooter.test.js","sourceRoot":"","sources":["../../src/__tests__/headerFooter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotatedTable.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/rotatedTable.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll } from 'vitest';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { PDFArray, PDFDict, PDFDocument, PDFName, PDFRawStream, decodePDFRawStream } from 'pdf-lib';
|
|
4
|
+
import fontkit from '@pdf-lib/fontkit';
|
|
5
|
+
import { buildDocument } from 'postext';
|
|
6
|
+
import { renderToPdf } from '../pdf-backend';
|
|
7
|
+
import { parseFontString } from '../fontString';
|
|
8
|
+
const fontBytes = fs.readFileSync(new URL('../../../../apps/web/public/fonts/Lora-Regular.ttf', import.meta.url));
|
|
9
|
+
const fontProvider = async () => new Uint8Array(fontBytes);
|
|
10
|
+
const face = fontkit.create(fontBytes);
|
|
11
|
+
class StubCtx {
|
|
12
|
+
font = '';
|
|
13
|
+
measureText(s) {
|
|
14
|
+
const sizePx = parseFontString(this.font)?.sizePx ?? 16;
|
|
15
|
+
const run = face.layout(s);
|
|
16
|
+
return { width: (run.advanceWidth / face.unitsPerEm) * sizePx };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
globalThis.OffscreenCanvas = class {
|
|
20
|
+
getContext() {
|
|
21
|
+
return new StubCtx();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const pt = (value) => ({ value, unit: 'pt' });
|
|
25
|
+
const cell = (content, extra = {}) => ({ content, ...extra });
|
|
26
|
+
const config = {
|
|
27
|
+
page: { width: pt(400), height: pt(500), margins: { top: pt(20), bottom: pt(20), left: pt(20), right: pt(20) } },
|
|
28
|
+
headings: { balancing: { enabled: false }, levels: [{ level: 1, breakBefore: { enabled: false } }] },
|
|
29
|
+
colorPalette: [{ id: 'ok', name: 'Compatible', value: { hex: '#c1dfd6', model: 'hex' } }],
|
|
30
|
+
};
|
|
31
|
+
const table = {
|
|
32
|
+
id: 'tab',
|
|
33
|
+
typeId: 'table',
|
|
34
|
+
kind: 'table',
|
|
35
|
+
caption: 'Services and benefits.',
|
|
36
|
+
note: ':swatch{color="ok"} compatible; :swatch{color="#e04148"} incompatible. See :ref{id="fig"}.',
|
|
37
|
+
createdAt: 0,
|
|
38
|
+
updatedAt: 0,
|
|
39
|
+
table: {
|
|
40
|
+
model: {
|
|
41
|
+
headerRowCount: 1,
|
|
42
|
+
rows: [
|
|
43
|
+
[cell('Service', { isHeader: true }), cell('Grade I', { isHeader: true }), cell('Grade II', { isHeader: true })],
|
|
44
|
+
[cell('Home care'), cell('Yes', { background: { hex: '#000000', model: 'hex', paletteId: 'ok' } }), cell('No', { background: { hex: '#e04148', model: 'hex' } })],
|
|
45
|
+
[cell('Day centre'), cell('See :ref{id="fig"}'), cell('Yes')],
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
placement: { rotate: 'ccw' },
|
|
50
|
+
};
|
|
51
|
+
const figure = {
|
|
52
|
+
id: 'fig',
|
|
53
|
+
typeId: 'figure',
|
|
54
|
+
kind: 'bitmap',
|
|
55
|
+
caption: 'A picture.',
|
|
56
|
+
createdAt: 0,
|
|
57
|
+
updatedAt: 0,
|
|
58
|
+
bitmap: { fileId: 'missing', format: 'png', width: 200, height: 100 },
|
|
59
|
+
};
|
|
60
|
+
const filler = (n) => Array.from({ length: n }, (_, i) => `Paragraph ${i} carries enough words to take a few lines of the narrow column so the flow advances.`).join('\n\n');
|
|
61
|
+
const markdown = `Intro :ref{id="tab"} and :ref{id="fig"} text.\n\n${filler(12)}`;
|
|
62
|
+
let pdf;
|
|
63
|
+
let doc;
|
|
64
|
+
let bytes;
|
|
65
|
+
beforeAll(async () => {
|
|
66
|
+
doc = buildDocument({ markdown, resources: [table, figure] }, config);
|
|
67
|
+
bytes = await renderToPdf(doc, { fontProvider });
|
|
68
|
+
pdf = await PDFDocument.load(bytes);
|
|
69
|
+
}, 60_000);
|
|
70
|
+
describe('a rotated table in the PDF', () => {
|
|
71
|
+
it('is placed turned on a page of its own', () => {
|
|
72
|
+
const placed = doc.pages.flatMap((p) => (p.floats ?? []).filter((b) => b.resourceBlock.resource.id === 'tab').map((b) => ({ page: p, block: b })));
|
|
73
|
+
expect(placed).toHaveLength(1);
|
|
74
|
+
expect(placed[0].block.resourceBlock.rotation?.direction).toBe('ccw');
|
|
75
|
+
});
|
|
76
|
+
it('draws the block through a quarter-turn matrix', () => {
|
|
77
|
+
const { page } = doc.pages.flatMap((p) => (p.floats ?? []).filter((b) => b.resourceBlock.resource.id === 'tab').map(() => ({ page: p })))[0];
|
|
78
|
+
const pdfPage = pdf.getPage(page.index);
|
|
79
|
+
const contents = pdfPage.node.Contents();
|
|
80
|
+
const streams = contents instanceof PDFArray
|
|
81
|
+
? contents.asArray().map((r) => pdf.context.lookup(r))
|
|
82
|
+
: [contents];
|
|
83
|
+
const text = streams
|
|
84
|
+
.map((s) => (s instanceof PDFRawStream ? Buffer.from(decodePDFRawStream(s).decode()).toString('latin1') : ''))
|
|
85
|
+
.join('\n');
|
|
86
|
+
// `0 1 -1 0 e f cm`: the counter-clockwise turn.
|
|
87
|
+
expect(/(^|\s)0 1 -1 0 [-\d.]+ [-\d.]+ cm/.test(text)).toBe(true);
|
|
88
|
+
// Balanced graphics state around it.
|
|
89
|
+
expect((text.match(/\bq\b/g) ?? []).length).toBe((text.match(/\bQ\b/g) ?? []).length);
|
|
90
|
+
});
|
|
91
|
+
it('turns the link annotation of a ref inside a cell with the block', () => {
|
|
92
|
+
const { page, block } = doc.pages.flatMap((p) => (p.floats ?? []).filter((b) => b.resourceBlock.resource.id === 'tab').map((b) => ({ page: p, block: b })))[0];
|
|
93
|
+
const pdfPage = pdf.getPage(page.index);
|
|
94
|
+
const annots = (pdfPage.node.Annots()?.asArray() ?? []).map((r) => pdf.context.lookup(r, PDFDict));
|
|
95
|
+
const links = annots.filter((a) => a.get(PDFName.of('Subtype')) === PDFName.of('Link'));
|
|
96
|
+
expect(links.length).toBeGreaterThanOrEqual(2); // the cell ref and the note ref
|
|
97
|
+
const scale = 72 / doc.config.page.dpi;
|
|
98
|
+
const h = pdfPage.getHeight();
|
|
99
|
+
for (const link of links) {
|
|
100
|
+
const rect = link.lookup(PDFName.of('Rect'), PDFArray).asArray().map((n) => n.asNumber());
|
|
101
|
+
const [x1, y1, x2, y2] = rect;
|
|
102
|
+
// Inside the band the block takes, in page space.
|
|
103
|
+
expect(x1).toBeGreaterThanOrEqual(block.bbox.x * scale - 0.5);
|
|
104
|
+
expect(x2).toBeLessThanOrEqual((block.bbox.x + block.bbox.width) * scale + 0.5);
|
|
105
|
+
expect(y1).toBeGreaterThanOrEqual(h - (block.bbox.y + block.bbox.height) * scale - 0.5);
|
|
106
|
+
expect(y2).toBeLessThanOrEqual(h - block.bbox.y * scale + 0.5);
|
|
107
|
+
// A turned label: taller than wide.
|
|
108
|
+
expect(y2 - y1).toBeGreaterThan(x2 - x1);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
//# sourceMappingURL=rotatedTable.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotatedTable.test.js","sourceRoot":"","sources":["../../src/__tests__/rotatedTable.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAa,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC/G,OAAO,OAAO,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,oDAAoD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAClH,MAAM,YAAY,GAAG,KAAK,IAAI,EAAE,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC;AAC3D,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAEvC,MAAM,OAAO;IACX,IAAI,GAAG,EAAE,CAAC;IACV,WAAW,CAAC,CAAS;QACnB,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,IAAI,EAAE,CAAC;QACxD,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC3B,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,MAAM,EAAE,CAAC;IAClE,CAAC;CACF;AACA,UAAsD,CAAC,eAAe,GAAG;IACxE,UAAU;QACR,OAAO,IAAI,OAAO,EAAE,CAAC;IACvB,CAAC;CACF,CAAC;AAEF,MAAM,EAAE,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAa,EAAE,CAAC,CAAC;AAC/D,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,QAA4B,EAAE,EAAa,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;AAErG,MAAM,MAAM,GAAkB;IAC5B,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;IAChH,QAAQ,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE;IACpG,YAAY,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;CAC1F,CAAC;AAEF,MAAM,KAAK,GAAa;IACtB,EAAE,EAAE,KAAK;IACT,MAAM,EAAE,OAAO;IACf,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,wBAAwB;IACjC,IAAI,EAAE,4FAA4F;IAClG,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;IACZ,KAAK,EAAE;QACL,KAAK,EAAE;YACL,cAAc,EAAE,CAAC;YACjB,IAAI,EAAE;gBACJ,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;gBAChH,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;gBACjK,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,oBAAoB,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;aAC9D;SACF;KACF;IACD,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;CAC7B,CAAC;AACF,MAAM,MAAM,GAAa;IACvB,EAAE,EAAE,KAAK;IACT,MAAM,EAAE,QAAQ;IAChB,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,YAAY;IACrB,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;IACZ,MAAM,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;CACtE,CAAC;AAEF,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,sFAAsF,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACzJ,MAAM,QAAQ,GAAG,oDAAoD,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AAElF,IAAI,GAAgB,CAAC;AACrB,IAAI,GAAqC,CAAC;AAC1C,IAAI,KAAiB,CAAC;AAEtB,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,GAAG,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACtE,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;IACjD,GAAG,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC,EAAE,MAAM,CAAC,CAAC;AAEX,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAc,CAAC,QAAQ,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACpJ,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,aAAc,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAc,CAAC,QAAQ,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC;QAC/I,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,QAAQ,YAAY,QAAQ;YAC1C,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACtD,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACf,MAAM,IAAI,GAAG,OAAO;aACjB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;aAC7G,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,iDAAiD;QACjD,MAAM,CAAC,mCAAmC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClE,qCAAqC;QACrC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAc,CAAC,QAAQ,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC;QACjK,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QACnG,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,KAAK,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;QACxF,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,gCAAgC;QAChF,MAAM,KAAK,GAAG,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QACvC,MAAM,CAAC,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;QAC9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAAe,CAAC,QAAQ,EAAE,CAAC,CAAC;YACzG,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,IAAwC,CAAC;YAClE,kDAAkD;YAClD,MAAM,CAAC,EAAE,CAAC,CAAC,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC;YAC9D,MAAM,CAAC,EAAE,CAAC,CAAC,mBAAmB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC;YAChF,MAAM,CAAC,EAAE,CAAC,CAAC,sBAAsB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC;YACxF,MAAM,CAAC,EAAE,CAAC,CAAC,mBAAmB,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC;YAC/D,oCAAoC;YACpC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,eAAe,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svgVector.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/svgVector.test.ts"],"names":[],"mappings":""}
|