From 5064b3cc42eaff63fb685d6dcd353f50ffe0f046 Mon Sep 17 00:00:00 2001 From: karthikmudunuri <102793643+karthikmudunuri@users.noreply.github.com> Date: Fri, 12 Jun 2026 16:10:36 +0530 Subject: [PATCH 1/3] fix(pptx/render): emit valid SVG for image-fill backgrounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit renderDeckToSvg rendered a slide's image-fill background as a CSS background shorthand inside fill="…" (center / cover no-repeat url("data:image…")) — invalid SVG that strict rasterisers (resvg, librsvg) reject, blocking a Chromium-free render path. The renderer now recognises a url(...) anywhere in the value and emits a real element (slice for cover, meet for contain). Adds a strict-XML-parser lock-in test over an image-background fixture. --- .changeset/render-image-bg-valid-svg.md | 20 +++++++ .../lib/render/__tests__/render-deck.test.ts | 52 +++++++++++++++++++ .../slidewise/src/lib/render/renderDeck.ts | 21 ++++++-- 3 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 .changeset/render-image-bg-valid-svg.md diff --git a/.changeset/render-image-bg-valid-svg.md b/.changeset/render-image-bg-valid-svg.md new file mode 100644 index 0000000..0a9f051 --- /dev/null +++ b/.changeset/render-image-bg-valid-svg.md @@ -0,0 +1,20 @@ +--- +"@textcortex/slidewise": patch +--- + +fix(render): emit a valid SVG `` for image-fill backgrounds + +`renderDeckToSvg` rendered a slide's image-fill background as a CSS `background` +shorthand inside an SVG `fill="…"` attribute — `fill="center / cover no-repeat +url("data:image…")"`. That is not valid SVG (a non-paint value plus nested +unescaped quotes); browsers tolerate it, but strict rasterisers +(`@resvg/resvg-js`, librsvg, batik) reject it, blocking a Chromium-free +`parsePptx → renderDeckToSvg → resvg → PNG` path. + +The pptx importer stores image backgrounds as a CSS shorthand, but the +renderer's image-ref detection only inspected the *start* of the value, so the +shorthand fell through to the `fill` path. The renderer now recognises a +`url(...)` anywhere in the value and emits a real `` element +(`preserveAspectRatio` = `slice` for `cover`, `meet` for `contain`). A lock-in +test asserts every rendered slide is valid SVG a strict XML parser accepts, +with an image-background slide as the regression case. diff --git a/packages/slidewise/src/lib/render/__tests__/render-deck.test.ts b/packages/slidewise/src/lib/render/__tests__/render-deck.test.ts index 2f5edef..4618c58 100644 --- a/packages/slidewise/src/lib/render/__tests__/render-deck.test.ts +++ b/packages/slidewise/src/lib/render/__tests__/render-deck.test.ts @@ -2,6 +2,7 @@ import { describe, it, expect } from "vitest"; import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import path from "node:path"; +import { XMLValidator } from "fast-xml-parser"; import { renderDeckToSvg, renderDeckToImages, @@ -146,6 +147,57 @@ describe("renderDeckToSvg / renderDeckToImages", () => { expect(w).toBe(480); }); + it("emits a real for an image-fill background, not a CSS-shorthand fill", async () => { + // The pptx importer stores image backgrounds as a CSS `background` + // shorthand: `center / cover no-repeat url("data:image…")`. The renderer + // must turn that into a valid SVG , never `fill="…url(data:…)…"` + // (nested quotes + a non-paint value that strict rasterisers reject). + const bg = `center / cover no-repeat url("${IMG_SRC}")`; + const deck = { + version: 1, + title: "ImageBg", + slides: [{ id: "s1", background: bg, elements: [] }], + } as Deck; + + const [svg] = await renderDeckToSvg(deck); + expect(svg).toContain(` { + const bg = `center / contain no-repeat url("${IMG_SRC}")`; + const deck = { + version: 1, + title: "ContainBg", + slides: [{ id: "s1", background: bg, elements: [] }], + } as Deck; + const [svg] = await renderDeckToSvg(deck); + expect(svg).toContain(`preserveAspectRatio="xMidYMid meet"`); + }); + + it("every rendered slide is valid SVG a strict XML parser accepts", async () => { + // Lock-in for the resvg/librsvg path: a strict (non-browser) parser must + // accept every slide. An image-background slide is the regression case. + const deck = { + version: 1, + title: "Strict", + slides: [ + { id: "s1", background: `center / cover no-repeat url("${IMG_SRC}")`, elements: [] }, + ...buildDeck().slides, + ], + } as Deck; + const svgs = await renderDeckToSvg(deck); + for (const svg of svgs) { + const result = XMLValidator.validate(svg); + expect(result, typeof result === "object" ? JSON.stringify(result.err) : "") + .toBe(true); + } + }); + it("stays browser-free (no Playwright/Puppeteer/jsdom in the source)", () => { const __dirname = path.dirname(fileURLToPath(import.meta.url)); const src = readFileSync(path.resolve(__dirname, "../renderDeck.ts"), "utf8"); diff --git a/packages/slidewise/src/lib/render/renderDeck.ts b/packages/slidewise/src/lib/render/renderDeck.ts index f64a6b4..6956866 100644 --- a/packages/slidewise/src/lib/render/renderDeck.ts +++ b/packages/slidewise/src/lib/render/renderDeck.ts @@ -163,9 +163,10 @@ function renderBackground(background: string | undefined): string { const fill = background ? solidFrom(background) : "#FFFFFF"; if (isImageRef(background)) { const href = imageHref(background!); + const preserve = imageFitPreserve(background); return ( `` + - `` + `` ); } return ``; @@ -499,12 +500,24 @@ async function defaultRasterize( // -- colour / string helpers ------------------------------------------------- function isImageRef(s: string | undefined): boolean { - return !!s && (s.startsWith("data:image") || /^url\(/i.test(s) || /^https?:\/\//i.test(s)); + if (!s) return false; + const v = s.trim(); + // A bare data/http URL, OR a CSS `background` shorthand that embeds a + // `url(...)` anywhere (e.g. `center / cover no-repeat url("data:image…")`, + // as produced by the pptx importer for image-fill backgrounds). + return v.startsWith("data:image") || /url\(/i.test(v) || /^https?:\/\//i.test(v); } function imageHref(s: string): string { - const m = /^url\(["']?(.*?)["']?\)$/i.exec(s); - return m ? m[1] : s; + // Pull the URL out of a `url(...)` wherever it appears in the value; data + // URLs use a `)`-free base64 alphabet, so non-greedy-to-first-`)` is safe. + const m = /url\(\s*["']?(.*?)["']?\s*\)/i.exec(s); + return m ? m[1] : s.trim(); +} + +/** `cover` → `slice`, `contain` → `meet`, for an image-fill shorthand. */ +function imageFitPreserve(s: string | undefined): string { + return s && /\bcontain\b/i.test(s) ? "xMidYMid meet" : "xMidYMid slice"; } /** Best-effort single colour for SVG: pass hex through, pull the first hex out From 3f9d393697c3ad485a6d84bf7134bd1b4bdf8483 Mon Sep 17 00:00:00 2001 From: karthikmudunuri <102793643+karthikmudunuri@users.noreply.github.com> Date: Fri, 12 Jun 2026 16:18:00 +0530 Subject: [PATCH 2/3] test(render): rasterise image-background slide through real @resvg/resvg-js XMLValidator proves well-formedness only; resvg is the actual consumer. Add @resvg/resvg-js as a devDependency and drive an image-background slide through the package's default rasteriser (no injected hook), asserting a valid PNG of the expected dimensions (320x180). resvg threw on the old fill="...url(data:...)..." output, so this is a true guard. --- packages/slidewise/package.json | 1 + .../lib/render/__tests__/render-deck.test.ts | 23 ++++ pnpm-lock.yaml | 130 ++++++++++++++++++ 3 files changed, 154 insertions(+) diff --git a/packages/slidewise/package.json b/packages/slidewise/package.json index afa1693..452e7c6 100644 --- a/packages/slidewise/package.json +++ b/packages/slidewise/package.json @@ -59,6 +59,7 @@ "zustand": "^5.0.12" }, "devDependencies": { + "@resvg/resvg-js": "^2.6.2", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@types/react": "^19", diff --git a/packages/slidewise/src/lib/render/__tests__/render-deck.test.ts b/packages/slidewise/src/lib/render/__tests__/render-deck.test.ts index 4618c58..072c9dd 100644 --- a/packages/slidewise/src/lib/render/__tests__/render-deck.test.ts +++ b/packages/slidewise/src/lib/render/__tests__/render-deck.test.ts @@ -198,6 +198,29 @@ describe("renderDeckToSvg / renderDeckToImages", () => { } }); + it("rasterises an image-background slide through real @resvg/resvg-js (the actual consumer)", async () => { + // The XMLValidator lock-in proves well-formedness; this proves the slide + // actually *renders* through resvg — the real point of the valid-SVG fix. + // No `rasterizeSvg` hook, so this drives the package's own default + // dynamic-`@resvg/resvg-js` path end-to-end. resvg threw on the old + // `fill="…url(data:…)…"` output ("expected space not 'd'"). + const deck = { + version: 1, + title: "ImageBgResvg", + slides: [{ id: "s1", background: `center / cover no-repeat url("${IMG_SRC}")`, elements: [] }], + } as Deck; + + const [png] = await renderDeckToImages(deck, { maxWidth: 320 }); + expect(png).toBeInstanceOf(Uint8Array); + expect(Array.from(png.subarray(0, 4))).toEqual([0x89, 0x50, 0x4e, 0x47]); // ‰PNG + // Decode the IHDR (bytes 16–23) and assert resvg produced a correctly + // *sized* raster of the 16:9 canvas — proof of a real render, not an empty + // buffer. 1920×1080 capped at width 320 → 320×180. + const view = new DataView(png.buffer, png.byteOffset, png.byteLength); + expect(view.getUint32(16)).toBe(320); // width + expect(view.getUint32(20)).toBe(180); // height + }); + it("stays browser-free (no Playwright/Puppeteer/jsdom in the source)", () => { const __dirname = path.dirname(fileURLToPath(import.meta.url)); const src = readFileSync(path.resolve(__dirname, "../renderDeck.ts"), "utf8"); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 426b19e..0387581 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -66,6 +66,9 @@ importers: specifier: ^5.0.12 version: 5.0.12(@types/react@19.2.14)(react@19.2.4) devDependencies: + '@resvg/resvg-js': + specifier: ^2.6.2 + version: 2.6.2 '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -611,6 +614,82 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@resvg/resvg-js-android-arm-eabi@2.6.2': + resolution: {integrity: sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==} + engines: {node: '>= 10'} + cpu: [arm] + os: [android] + + '@resvg/resvg-js-android-arm64@2.6.2': + resolution: {integrity: sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@resvg/resvg-js-darwin-arm64@2.6.2': + resolution: {integrity: sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@resvg/resvg-js-darwin-x64@2.6.2': + resolution: {integrity: sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@resvg/resvg-js-linux-arm-gnueabihf@2.6.2': + resolution: {integrity: sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@resvg/resvg-js-linux-arm64-gnu@2.6.2': + resolution: {integrity: sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@resvg/resvg-js-linux-arm64-musl@2.6.2': + resolution: {integrity: sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@resvg/resvg-js-linux-x64-gnu@2.6.2': + resolution: {integrity: sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@resvg/resvg-js-linux-x64-musl@2.6.2': + resolution: {integrity: sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@resvg/resvg-js-win32-arm64-msvc@2.6.2': + resolution: {integrity: sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@resvg/resvg-js-win32-ia32-msvc@2.6.2': + resolution: {integrity: sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@resvg/resvg-js-win32-x64-msvc@2.6.2': + resolution: {integrity: sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@resvg/resvg-js@2.6.2': + resolution: {integrity: sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==} + engines: {node: '>= 10'} + '@rolldown/pluginutils@1.0.0-rc.3': resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} @@ -2688,6 +2767,57 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 + '@resvg/resvg-js-android-arm-eabi@2.6.2': + optional: true + + '@resvg/resvg-js-android-arm64@2.6.2': + optional: true + + '@resvg/resvg-js-darwin-arm64@2.6.2': + optional: true + + '@resvg/resvg-js-darwin-x64@2.6.2': + optional: true + + '@resvg/resvg-js-linux-arm-gnueabihf@2.6.2': + optional: true + + '@resvg/resvg-js-linux-arm64-gnu@2.6.2': + optional: true + + '@resvg/resvg-js-linux-arm64-musl@2.6.2': + optional: true + + '@resvg/resvg-js-linux-x64-gnu@2.6.2': + optional: true + + '@resvg/resvg-js-linux-x64-musl@2.6.2': + optional: true + + '@resvg/resvg-js-win32-arm64-msvc@2.6.2': + optional: true + + '@resvg/resvg-js-win32-ia32-msvc@2.6.2': + optional: true + + '@resvg/resvg-js-win32-x64-msvc@2.6.2': + optional: true + + '@resvg/resvg-js@2.6.2': + optionalDependencies: + '@resvg/resvg-js-android-arm-eabi': 2.6.2 + '@resvg/resvg-js-android-arm64': 2.6.2 + '@resvg/resvg-js-darwin-arm64': 2.6.2 + '@resvg/resvg-js-darwin-x64': 2.6.2 + '@resvg/resvg-js-linux-arm-gnueabihf': 2.6.2 + '@resvg/resvg-js-linux-arm64-gnu': 2.6.2 + '@resvg/resvg-js-linux-arm64-musl': 2.6.2 + '@resvg/resvg-js-linux-x64-gnu': 2.6.2 + '@resvg/resvg-js-linux-x64-musl': 2.6.2 + '@resvg/resvg-js-win32-arm64-msvc': 2.6.2 + '@resvg/resvg-js-win32-ia32-msvc': 2.6.2 + '@resvg/resvg-js-win32-x64-msvc': 2.6.2 + '@rolldown/pluginutils@1.0.0-rc.3': {} '@rollup/rollup-android-arm-eabi@4.60.2': From b6bca12ac2f0f94030cdcb5b287b487f2338c60a Mon Sep 17 00:00:00 2001 From: karthikmudunuri <102793643+karthikmudunuri@users.noreply.github.com> Date: Fri, 12 Jun 2026 16:23:14 +0530 Subject: [PATCH 3/3] Revert "test(render): rasterise image-background slide through real @resvg/resvg-js" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 3f9d393. Keep the resvg renderability check on the consumer side (the host serializer already ships @resvg/resvg-js) rather than dragging a platform-native binary into the package's CI. The bug was an SVG-validity (well-formedness) regression, which the pure-JS XMLValidator lock-in already catches — it was confirmed to reject the old malformed output. The package CI stays native-dep-free. --- packages/slidewise/package.json | 1 - .../lib/render/__tests__/render-deck.test.ts | 23 ---- pnpm-lock.yaml | 130 ------------------ 3 files changed, 154 deletions(-) diff --git a/packages/slidewise/package.json b/packages/slidewise/package.json index 452e7c6..afa1693 100644 --- a/packages/slidewise/package.json +++ b/packages/slidewise/package.json @@ -59,7 +59,6 @@ "zustand": "^5.0.12" }, "devDependencies": { - "@resvg/resvg-js": "^2.6.2", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@types/react": "^19", diff --git a/packages/slidewise/src/lib/render/__tests__/render-deck.test.ts b/packages/slidewise/src/lib/render/__tests__/render-deck.test.ts index 072c9dd..4618c58 100644 --- a/packages/slidewise/src/lib/render/__tests__/render-deck.test.ts +++ b/packages/slidewise/src/lib/render/__tests__/render-deck.test.ts @@ -198,29 +198,6 @@ describe("renderDeckToSvg / renderDeckToImages", () => { } }); - it("rasterises an image-background slide through real @resvg/resvg-js (the actual consumer)", async () => { - // The XMLValidator lock-in proves well-formedness; this proves the slide - // actually *renders* through resvg — the real point of the valid-SVG fix. - // No `rasterizeSvg` hook, so this drives the package's own default - // dynamic-`@resvg/resvg-js` path end-to-end. resvg threw on the old - // `fill="…url(data:…)…"` output ("expected space not 'd'"). - const deck = { - version: 1, - title: "ImageBgResvg", - slides: [{ id: "s1", background: `center / cover no-repeat url("${IMG_SRC}")`, elements: [] }], - } as Deck; - - const [png] = await renderDeckToImages(deck, { maxWidth: 320 }); - expect(png).toBeInstanceOf(Uint8Array); - expect(Array.from(png.subarray(0, 4))).toEqual([0x89, 0x50, 0x4e, 0x47]); // ‰PNG - // Decode the IHDR (bytes 16–23) and assert resvg produced a correctly - // *sized* raster of the 16:9 canvas — proof of a real render, not an empty - // buffer. 1920×1080 capped at width 320 → 320×180. - const view = new DataView(png.buffer, png.byteOffset, png.byteLength); - expect(view.getUint32(16)).toBe(320); // width - expect(view.getUint32(20)).toBe(180); // height - }); - it("stays browser-free (no Playwright/Puppeteer/jsdom in the source)", () => { const __dirname = path.dirname(fileURLToPath(import.meta.url)); const src = readFileSync(path.resolve(__dirname, "../renderDeck.ts"), "utf8"); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0387581..426b19e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -66,9 +66,6 @@ importers: specifier: ^5.0.12 version: 5.0.12(@types/react@19.2.14)(react@19.2.4) devDependencies: - '@resvg/resvg-js': - specifier: ^2.6.2 - version: 2.6.2 '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -614,82 +611,6 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@resvg/resvg-js-android-arm-eabi@2.6.2': - resolution: {integrity: sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==} - engines: {node: '>= 10'} - cpu: [arm] - os: [android] - - '@resvg/resvg-js-android-arm64@2.6.2': - resolution: {integrity: sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - - '@resvg/resvg-js-darwin-arm64@2.6.2': - resolution: {integrity: sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@resvg/resvg-js-darwin-x64@2.6.2': - resolution: {integrity: sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@resvg/resvg-js-linux-arm-gnueabihf@2.6.2': - resolution: {integrity: sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - - '@resvg/resvg-js-linux-arm64-gnu@2.6.2': - resolution: {integrity: sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@resvg/resvg-js-linux-arm64-musl@2.6.2': - resolution: {integrity: sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@resvg/resvg-js-linux-x64-gnu@2.6.2': - resolution: {integrity: sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@resvg/resvg-js-linux-x64-musl@2.6.2': - resolution: {integrity: sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@resvg/resvg-js-win32-arm64-msvc@2.6.2': - resolution: {integrity: sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@resvg/resvg-js-win32-ia32-msvc@2.6.2': - resolution: {integrity: sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - - '@resvg/resvg-js-win32-x64-msvc@2.6.2': - resolution: {integrity: sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@resvg/resvg-js@2.6.2': - resolution: {integrity: sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==} - engines: {node: '>= 10'} - '@rolldown/pluginutils@1.0.0-rc.3': resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} @@ -2767,57 +2688,6 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@resvg/resvg-js-android-arm-eabi@2.6.2': - optional: true - - '@resvg/resvg-js-android-arm64@2.6.2': - optional: true - - '@resvg/resvg-js-darwin-arm64@2.6.2': - optional: true - - '@resvg/resvg-js-darwin-x64@2.6.2': - optional: true - - '@resvg/resvg-js-linux-arm-gnueabihf@2.6.2': - optional: true - - '@resvg/resvg-js-linux-arm64-gnu@2.6.2': - optional: true - - '@resvg/resvg-js-linux-arm64-musl@2.6.2': - optional: true - - '@resvg/resvg-js-linux-x64-gnu@2.6.2': - optional: true - - '@resvg/resvg-js-linux-x64-musl@2.6.2': - optional: true - - '@resvg/resvg-js-win32-arm64-msvc@2.6.2': - optional: true - - '@resvg/resvg-js-win32-ia32-msvc@2.6.2': - optional: true - - '@resvg/resvg-js-win32-x64-msvc@2.6.2': - optional: true - - '@resvg/resvg-js@2.6.2': - optionalDependencies: - '@resvg/resvg-js-android-arm-eabi': 2.6.2 - '@resvg/resvg-js-android-arm64': 2.6.2 - '@resvg/resvg-js-darwin-arm64': 2.6.2 - '@resvg/resvg-js-darwin-x64': 2.6.2 - '@resvg/resvg-js-linux-arm-gnueabihf': 2.6.2 - '@resvg/resvg-js-linux-arm64-gnu': 2.6.2 - '@resvg/resvg-js-linux-arm64-musl': 2.6.2 - '@resvg/resvg-js-linux-x64-gnu': 2.6.2 - '@resvg/resvg-js-linux-x64-musl': 2.6.2 - '@resvg/resvg-js-win32-arm64-msvc': 2.6.2 - '@resvg/resvg-js-win32-ia32-msvc': 2.6.2 - '@resvg/resvg-js-win32-x64-msvc': 2.6.2 - '@rolldown/pluginutils@1.0.0-rc.3': {} '@rollup/rollup-android-arm-eabi@4.60.2':