| 1 | import assert from "node:assert/strict"; |
| 2 | import { |
| 3 | createRasterPdf, |
| 4 | isSafeInlineExportImage, |
| 5 | neutralizeExternalCssResources, |
| 6 | planRasterSlices, |
| 7 | transformExportMarkdownUrl, |
| 8 | } from "../lib/sessionExportCore"; |
| 9 | |
| 10 | const css = neutralizeExternalCssResources(` |
| 11 | @font-face { font-family: Test; src: url("fonts/test.woff2") format("woff2"); } |
| 12 | .safe { color: red; background-image: url(https://example.com/image.png); } |
| 13 | `); |
| 14 | assert.equal(css.includes("url("), false); |
| 15 | assert.match(css, /\.safe \{ color: red;/); |
| 16 | |
| 17 | assert.deepEqual(planRasterSlices(25_000, 8_000), [ |
| 18 | { offset: 0, height: 8_000 }, |
| 19 | { offset: 8_000, height: 8_000 }, |
| 20 | { offset: 16_000, height: 8_000 }, |
| 21 | { offset: 24_000, height: 1_000 }, |
| 22 | ]); |
| 23 | assert.deepEqual(planRasterSlices(Number.NaN, 0), [{ offset: 0, height: 1 }]); |
| 24 | assert.deepEqual(planRasterSlices(25_000, 8_000, [7_000, 14_200, 23_000]), [ |
| 25 | { offset: 0, height: 7_000 }, |
| 26 | { offset: 7_000, height: 7_200 }, |
| 27 | { offset: 14_200, height: 8_000 }, |
| 28 | { offset: 22_200, height: 2_800 }, |
| 29 | ]); |
| 30 | assert.deepEqual(planRasterSlices(1_400, 1_354, [1_352], 1_352), [ |
| 31 | { offset: 0, height: 1_354 }, |
| 32 | ]); |
| 33 | assert.deepEqual(planRasterSlices(1_048, 1_000, [1_000], 1_000), [ |
| 34 | { offset: 0, height: 1_000 }, |
| 35 | ]); |
| 36 | assert.deepEqual(planRasterSlices(2_048, 1_000, [900, 1_950], 1_950), [ |
| 37 | { offset: 0, height: 900 }, |
| 38 | { offset: 900, height: 1_000 }, |
| 39 | { offset: 1_900, height: 148 }, |
| 40 | ]); |
| 41 | |
| 42 | assert.equal(isSafeInlineExportImage("data:image/png;base64,iVBORw0KGgo="), true); |
| 43 | assert.equal(isSafeInlineExportImage(" DATA:IMAGE/JPEG;BASE64,/9j/4AAQ "), true); |
| 44 | assert.equal(isSafeInlineExportImage("data:image/webp;base64,UklGRg=="), true); |
| 45 | assert.equal(isSafeInlineExportImage("data:image/gif;base64,R0lGODlh"), true); |
| 46 | assert.equal(isSafeInlineExportImage("https://example.com/image.png"), false); |
| 47 | assert.equal(isSafeInlineExportImage("file:///tmp/image.png"), false); |
| 48 | assert.equal(isSafeInlineExportImage("data:image/svg+xml;base64,PHN2Zz4="), false); |
| 49 | assert.equal(isSafeInlineExportImage("data:image/png,not-base64"), false); |
| 50 | assert.equal(isSafeInlineExportImage("data:image/png;base64,not base64"), false); |
| 51 | assert.equal(isSafeInlineExportImage("data:image/png;base64,invalid!"), false); |
| 52 | |
| 53 | const fallbackUrlTransform = (value: string) => `filtered:${value}`; |
| 54 | assert.equal( |
| 55 | transformExportMarkdownUrl(" data:image/png;base64,iVBORw0KGgo= ", "src", fallbackUrlTransform), |
| 56 | "data:image/png;base64,iVBORw0KGgo=", |
| 57 | ); |
| 58 | assert.equal( |
| 59 | transformExportMarkdownUrl("data:image/png;base64,iVBORw0KGgo=", "href", fallbackUrlTransform), |
| 60 | "filtered:data:image/png;base64,iVBORw0KGgo=", |
| 61 | ); |
| 62 | assert.equal( |
| 63 | transformExportMarkdownUrl("https://example.com/image.png", "src", fallbackUrlTransform), |
| 64 | "filtered:https://example.com/image.png", |
| 65 | ); |
| 66 | |
| 67 | const pdf = createRasterPdf( |
| 68 | [ |
| 69 | { bytes: new Uint8Array([0xff, 0xd8, 0xff, 0xd9]), width: 100, height: 120 }, |
| 70 | { bytes: new Uint8Array([0xff, 0xd8, 0xff, 0xd9]), width: 100, height: 80 }, |
| 71 | ], |
| 72 | "Export test", |
| 73 | ); |
| 74 | const pdfText = new TextDecoder("latin1").decode(pdf); |
| 75 | assert.equal(pdfText.startsWith("%PDF-1.4"), true); |
| 76 | assert.match(pdfText, /\/Count 2/); |
| 77 | assert.equal((pdfText.match(/\/Subtype \/Image/g) ?? []).length, 2); |
| 78 | assert.match(pdfText, /startxref\n\d+\n%%EOF/); |
| 79 | |
| 80 | console.log("session export tests passed"); |
| 81 |