@silurus/ooxml 0.75.5 → 0.76.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.
- package/README.md +66 -28
- package/dist/bounded-raw-part-cache-C6ro6Ezf.js +254 -0
- package/dist/{find-cursor-Dc5iM6s7.js → canvas-viewer-mechanics-CwVSOYke.js} +192 -64
- package/dist/{document-pull-client-BcNYhoAG.js → document-pull-client-AAnwzlig.js} +3625 -3601
- package/dist/docx-CCksIXd5.js +1301 -0
- package/dist/docx.mjs +4 -6
- package/dist/docx_parser_bg.wasm +0 -0
- package/dist/index.mjs +3 -3
- package/dist/{line-distribute-B8sqT8kC.js → line-distribute-C1r2zvji.js} +141 -141
- package/dist/{line-metrics-D9gqQWHl.js → line-metrics-BdCACYlq.js} +4026 -1170
- package/dist/math.mjs +1 -1
- package/dist/node.mjs +779 -465
- package/dist/pptx-CKAk5e-J.js +1735 -0
- package/dist/pptx.mjs +5 -7
- package/dist/pptx_parser_bg.wasm +0 -0
- package/dist/{render-CalC7GX4.js → render-CLcpSi0m.js} +11 -18
- package/dist/render-worker-host-B8HAb_sK.js +27 -0
- package/dist/render-worker-host-Bkf1jUcW.js +27 -0
- package/dist/render-worker-host-CKOmXdyr.js +27 -0
- package/dist/resource-measurement-E_S_iau4.js +119 -0
- package/dist/session-B4Y54cbT.js +730 -0
- package/dist/{renderer-B9R6F_QY.js → slide-pull-client-WCuYCjio.js} +973 -820
- package/dist/types/docx.d.ts +1181 -3994
- package/dist/types/index.d.ts +2733 -8171
- package/dist/types/math.d.ts +8 -33
- package/dist/types/node.d.ts +1852 -4433
- package/dist/types/pptx.d.ts +1030 -3678
- package/dist/types/xlsx.d.ts +1291 -3262
- package/dist/worksheet-pull-client-YzjJMOns.js +455 -0
- package/dist/xlsx-BBmmZNQn.js +6362 -0
- package/dist/xlsx.mjs +5 -7
- package/dist/xlsx_parser_bg.wasm +0 -0
- package/package.json +14 -7
- package/dist/bounded-raw-part-cache-BTfZD_Sz.js +0 -1248
- package/dist/docx-DjF8FgoP.js +0 -1274
- package/dist/duotone-bitmap-by-path-CWsSJkJu.js +0 -28
- package/dist/hyperlink-D85FexTa.js +0 -27
- package/dist/pptx-C17xP8AV.js +0 -1705
- package/dist/pptx-Dl8tOSmP.js +0 -822
- package/dist/preload-BEouWnlI.js +0 -132
- package/dist/render-worker-host-BG3a7brz.js +0 -27
- package/dist/render-worker-host-CsB-dPJv.js +0 -27
- package/dist/render-worker-host-Cyv5Hkbh.js +0 -27
- package/dist/resource-measurement-6aReN3K0.js +0 -93
- package/dist/slide-pull-client-D_T0AIoX.js +0 -175
- package/dist/svg-image-by-path-C1M3N2pT.js +0 -1623
- package/dist/worksheet-pull-worker-DCei8u-4.js +0 -347
- package/dist/xlsx-BaH9irS0.js +0 -5515
- /package/dist/{highlight-rect-cCvVU-MW.js → highlight-rect-CAkCWJ37.js} +0 -0
- /package/dist/{mathjax-Dqo857oC.js → mathjax-CMjda8Ip.js} +0 -0
- /package/dist/{transfer-3QEJrsJa.js → transfer-DCu4c2BL.js} +0 -0
- /package/dist/{visible-index-CKvgpUrf.js → visible-index-CgyJLAS_.js} +0 -0
package/README.md
CHANGED
|
@@ -79,12 +79,12 @@ pnpm add @silurus/ooxml
|
|
|
79
79
|
|
|
80
80
|
```typescript
|
|
81
81
|
import { DocxViewer } from '@silurus/ooxml/docx';
|
|
82
|
-
import { XlsxViewer } from '@silurus/ooxml/xlsx';
|
|
82
|
+
import { XlsxSheetViewer, XlsxViewer, XlsxWorkbook } from '@silurus/ooxml/xlsx';
|
|
83
83
|
import { PptxViewer } from '@silurus/ooxml/pptx';
|
|
84
84
|
|
|
85
85
|
// DOCX — caller provides the <canvas>
|
|
86
|
-
const
|
|
87
|
-
const docx = new DocxViewer(
|
|
86
|
+
const docxCanvas = document.getElementById('docx-canvas') as HTMLCanvasElement;
|
|
87
|
+
const docx = new DocxViewer(docxCanvas);
|
|
88
88
|
await docx.load('/document.docx');
|
|
89
89
|
docx.nextPage();
|
|
90
90
|
|
|
@@ -93,9 +93,32 @@ const container = document.getElementById('xlsx-container') as HTMLElement;
|
|
|
93
93
|
const xlsx = new XlsxViewer(container);
|
|
94
94
|
await xlsx.load('/workbook.xlsx');
|
|
95
95
|
|
|
96
|
+
// XLSX active-sheet surface only — caller provides the <canvas>
|
|
97
|
+
const sheetCanvas = document.getElementById('xlsx-canvas') as HTMLCanvasElement;
|
|
98
|
+
const sheet = new XlsxSheetViewer(sheetCanvas);
|
|
99
|
+
await sheet.load('/workbook.xlsx');
|
|
100
|
+
await sheet.goToSheet(1);
|
|
101
|
+
|
|
102
|
+
// Share one parsed workbook across independently scrollable sheet canvases,
|
|
103
|
+
// including canvases created in same-origin popup windows.
|
|
104
|
+
const workbook = await XlsxWorkbook.load('/workbook.xlsx');
|
|
105
|
+
const firstCanvas = document.getElementById('xlsx-first-canvas') as HTMLCanvasElement;
|
|
106
|
+
const secondCanvas = document.getElementById('xlsx-second-canvas') as HTMLCanvasElement;
|
|
107
|
+
const firstSheet = XlsxSheetViewer.fromWorkbook(firstCanvas, workbook);
|
|
108
|
+
const secondSheet = XlsxSheetViewer.fromWorkbook(secondCanvas, workbook);
|
|
109
|
+
await Promise.all([
|
|
110
|
+
firstSheet.goToSheet(0),
|
|
111
|
+
secondSheet.goToSheet(1),
|
|
112
|
+
]);
|
|
113
|
+
|
|
114
|
+
// Each viewer borrows the workbook; the caller closes it after the viewers.
|
|
115
|
+
firstSheet.destroy();
|
|
116
|
+
secondSheet.destroy();
|
|
117
|
+
workbook.destroy();
|
|
118
|
+
|
|
96
119
|
// PPTX — caller provides the <canvas>
|
|
97
|
-
const
|
|
98
|
-
const pptx = new PptxViewer(
|
|
120
|
+
const pptxCanvas = document.getElementById('pptx-canvas') as HTMLCanvasElement;
|
|
121
|
+
const pptx = new PptxViewer(pptxCanvas);
|
|
99
122
|
await pptx.load('/deck.pptx');
|
|
100
123
|
pptx.nextSlide();
|
|
101
124
|
```
|
|
@@ -203,7 +226,7 @@ The container must have a bounded height (e.g. `height: 100vh` or a flex child)
|
|
|
203
226
|
so the viewer can size its scroll host to it. Base zoom fits the first page/slide
|
|
204
227
|
width to the container width and re-fits on resize; a `0`-width container defers
|
|
205
228
|
layout until it has width. Call `destroy()` to tear down (a self-loaded engine is
|
|
206
|
-
destroyed with it;
|
|
229
|
+
destroyed with it; a borrowed one is not — see below).
|
|
207
230
|
|
|
208
231
|
Pass `refitOnResize: false` when the viewport must not determine the document's
|
|
209
232
|
physical display size. An explicit pre-load `setScale(1)` then keeps the same
|
|
@@ -255,26 +278,38 @@ Pass `enableHyperlinks: false` to disable hyperlink interactivity entirely — n
|
|
|
255
278
|
hit-testing, no pointer cursor over links, no default navigation, and
|
|
256
279
|
`onHyperlinkClick` is never called; links still render as authored but are inert.
|
|
257
280
|
This applies to every viewer that supports hyperlinks (`DocxViewer`,
|
|
258
|
-
`DocxScrollViewer`, `PptxViewer`, `PptxScrollViewer`, `XlsxViewer
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
281
|
+
`DocxScrollViewer`, `PptxViewer`, `PptxScrollViewer`, `XlsxViewer`,
|
|
282
|
+
`XlsxSheetViewer`).
|
|
283
|
+
|
|
284
|
+
**Choose one loading mode.** For the normal one-view case, construct a Viewer and
|
|
285
|
+
call `viewer.load(source)`: the Viewer owns the parsed engine, may replace it on a
|
|
286
|
+
later load, and destroys it during teardown. For master–detail, multi-pane, or
|
|
287
|
+
multi-window UIs, create the Viewer from an already-loaded headless engine so
|
|
288
|
+
every view shares **one** parse. The two modes are mutually exclusive: on a
|
|
289
|
+
Viewer returned by a `from*()` factory, `load()` is unsupported, the engine's
|
|
290
|
+
own `mode` wins, and `destroy()` leaves the borrowed engine intact — the caller
|
|
291
|
+
owns its lifecycle.
|
|
292
|
+
|
|
293
|
+
| Use case | Acquisition | Engine owner |
|
|
294
|
+
| --- | --- | --- |
|
|
295
|
+
| One Viewer | `new Viewer(target)` then `viewer.load(source)` | Viewer |
|
|
296
|
+
| Shared parse | `Engine.load(source)` then `Viewer.fromDocument / fromPresentation / fromWorkbook(...)` | Caller |
|
|
265
297
|
|
|
266
298
|
```typescript
|
|
267
|
-
import { DocxDocument, DocxScrollViewer } from '@silurus/ooxml/docx';
|
|
268
|
-
|
|
269
|
-
const
|
|
270
|
-
const scroll =
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
299
|
+
import { DocxDocument, DocxScrollViewer, DocxViewer } from '@silurus/ooxml/docx';
|
|
300
|
+
|
|
301
|
+
const document = await DocxDocument.load('/document.docx'); // parse once
|
|
302
|
+
const scroll = DocxScrollViewer.fromDocument(container, document);
|
|
303
|
+
const page = DocxViewer.fromDocument(canvas, document);
|
|
304
|
+
await page.goToPage(0);
|
|
305
|
+
// ...also drive a thumbnail grid or more panes from the same document.
|
|
306
|
+
page.destroy();
|
|
307
|
+
scroll.destroy(); // the borrowed document is NOT destroyed — you own it
|
|
308
|
+
document.destroy(); // release it yourself when every pane is gone
|
|
274
309
|
```
|
|
275
310
|
|
|
276
|
-
`
|
|
277
|
-
|
|
311
|
+
`PptxViewer` and `PptxScrollViewer` use `fromPresentation(...)`; `XlsxViewer`
|
|
312
|
+
and `XlsxSheetViewer` use `fromWorkbook(...)`.
|
|
278
313
|
|
|
279
314
|
For presentations, `enableMediaPlayback: true` makes embedded audio and video
|
|
280
315
|
interactive inside the real viewport plus `mediaOverscan` slides. Other mounted
|
|
@@ -463,7 +498,7 @@ file without uploading it.
|
|
|
463
498
|
| | In-document find (`findText` / `findNext` / `findPrev` / `clearFind` — full-text search, all hits highlighted, each match tagged with its page) | ✅ |
|
|
464
499
|
| | Runtime zoom (`getScale` / `setScale` / `fitWidth` / `fitPage`) | ✅ |
|
|
465
500
|
| | Clickable hyperlinks (overlay hit-test, `onHyperlinkClick`; internal bookmark / anchor navigation) | ✅ |
|
|
466
|
-
| | Continuous scroll viewer (`DocxScrollViewer` — virtualized page list, desk background / shadow, Ctrl/⌘+wheel zoom, engine
|
|
501
|
+
| | Continuous scroll viewer (`DocxScrollViewer` — virtualized page list, desk background / shadow, Ctrl/⌘+wheel zoom, borrowed-engine factory) | ✅ |
|
|
467
502
|
| **Loading** | Password-protected files ([MS-OFFCRYPTO] Agile Encryption — `load(bytes, { password })`, decrypted client-side via WebCrypto; legacy Standard / Extensible encryption → typed `unsupported-encryption`) | ✅ |
|
|
468
503
|
|
|
469
504
|
---
|
|
@@ -624,7 +659,7 @@ file without uploading it.
|
|
|
624
659
|
| | In-document find (`findText` / `findNext` / `findPrev` / `clearFind` — matches tagged with slide) | ✅ |
|
|
625
660
|
| | Runtime zoom (`getScale` / `setScale` / `fitWidth` / `fitPage`) | ✅ |
|
|
626
661
|
| | Clickable hyperlinks (`onHyperlinkClick`; internal slide-jump navigation) | ✅ |
|
|
627
|
-
| | Continuous scroll viewer (`PptxScrollViewer` — virtualized slide list, desk background / shadow, Ctrl/⌘+wheel zoom, engine
|
|
662
|
+
| | Continuous scroll viewer (`PptxScrollViewer` — virtualized slide list, desk background / shadow, Ctrl/⌘+wheel zoom, borrowed-engine factory) | ✅ |
|
|
628
663
|
| **Loading** | Password-protected files ([MS-OFFCRYPTO] Agile Encryption — `load(bytes, { password })`, decrypted client-side via WebCrypto; legacy Standard / Extensible encryption → typed `unsupported-encryption`) | ✅ |
|
|
629
664
|
|
|
630
665
|
---
|
|
@@ -636,7 +671,8 @@ file without uploading it.
|
|
|
636
671
|
## Companion packages
|
|
637
672
|
|
|
638
673
|
- **[`packages/markdown/`](packages/markdown/)** — `@silurus/ooxml-markdown` and the `ooxml-md` CLI convert `.pptx` / `.docx` / `.xlsx` to GitHub-flavoured markdown via the workspace WASM parsers. Same projection used by the MCP server (~21× smaller than the raw XML on the demo deck, ~8% bigger than a flat-text extractor). Includes a node20-based GitHub Action for bulk repo-wide conversion.
|
|
639
|
-
- **[`packages/node/`](packages/node/)** — the implementation behind the public Node-only `@silurus/ooxml/node` subpath.
|
|
674
|
+
- **[`packages/node/`](packages/node/)** — the implementation behind the public Node-only `@silurus/ooxml/node` subpath. Its canonical APIs are the explicitly owned, bounded `openPptxPresentation`, `openDocxDocument`, and `openXlsxWorkbook` sessions. Async `materializePptxPresentation`, `materializeDocxDocument`, `materializeXlsxWorkbookIndex`, `materializeXlsxWorksheet`, and `materializeXlsxWorkbook` are provided when a complete caller-owned graph is actually needed. Each `open*` call returns an explicit, idempotent `close()`-able session; PPTX streams `slides()`, DOCX completes format-required sequential pagination before streaming `pages()`, and XLSX parses its workbook index once before sequential `worksheetRows(sheetIndex)` streams reuse the retained archive. Useful for CI checks and headless rendering pipelines; canvas rendering accepts a user-supplied backend such as `skia-canvas` without making it a runtime dependency.
|
|
675
|
+
See the [0.75 to 0.76 migration guide](docs/migration-0.76.md) for every removed synchronous helper and its replacement.
|
|
640
676
|
- **[`packages/vscode-extension/`](packages/vscode-extension/)** — VS Code extension (`ooxml-viewer`) that registers `CustomEditorProvider`s for `.docx`, `.xlsx`, and `.pptx`, and (opt-in) auto-installs and registers the `ooxml-mcp-server` so AI coding agents in the same window (Copilot Agent mode, Claude, …) can read those files via dedicated tools. The preview is offline by default; an opt-in `ooxmlViewer.useGoogleFonts` setting (off, and force-disabled in untrusted workspaces) surfaces the library's metric-compatible font substitution, widening the webview CSP to the Google Fonts CDN only while enabled.
|
|
641
677
|
- **[`packages/mcp-server/`](packages/mcp-server/)** — Rust MCP server (`ooxml-mcp-server`) exposing the parsers as tools for AI agents (Claude, Copilot, Codex, etc.). Provides structured queries (`docx_get_structure`, `xlsx_get_cell_range`, `pptx_get_slide_structure`, …) so agents can inspect OOXML files without shelling out to `unzip`. Prebuilt binaries are attached to each [GitHub Release](https://github.com/yukiyokotani/office-open-xml-viewer/releases) for macOS / Linux / Windows; the VS Code extension downloads them on demand.
|
|
642
678
|
|
|
@@ -738,16 +774,17 @@ await viewer.load(file);
|
|
|
738
774
|
## Security & Privacy
|
|
739
775
|
|
|
740
776
|
- **Canvas-only rendering.** Documents are decoded and drawn to an `HTMLCanvasElement`. No script, link, form, or other active content from the source file is executed or injected into the DOM.
|
|
741
|
-
- **Bounded OOXML package expansion.** DOCX, XLSX, and PPTX use the same resource policy. By default, one archive entry may inflate to at most 128 MiB
|
|
777
|
+
- **Bounded OOXML package expansion.** DOCX, XLSX, and PPTX use the same resource policy. By default, one archive entry may inflate to at most 128 MiB, the distinct entries visited during one package session may inflate to at most 256 MiB, and an archive may contain at most 4,096 entries. Override these budgets with a plain `resourceLimits` object on a viewer or `load(...)` call:
|
|
742
778
|
```ts
|
|
743
779
|
new XlsxViewer(container, {
|
|
744
780
|
resourceLimits: {
|
|
745
781
|
maxArchiveEntryBytes: 64 * 1024 * 1024,
|
|
746
782
|
maxTotalInflatedBytes: 192 * 1024 * 1024,
|
|
783
|
+
maxArchiveEntries: 2048,
|
|
747
784
|
},
|
|
748
785
|
});
|
|
749
786
|
```
|
|
750
|
-
`maxArchiveEntryBytes` applies to every XML, text, image, media, and other package part that the parser reads. `maxTotalInflatedBytes` counts the largest amount actually read from each distinct part during the lifetime of the loaded package; reading the same part again does not consume that budget twice. Set an individual field to `null` to disable that configurable budget. Internal hard safety ceilings still apply, so disabling a budget does not make arbitrary archives acceptable. Values other than `null` must be positive safe
|
|
787
|
+
`maxArchiveEntryBytes` applies to every XML, text, image, media, and other package part that the parser reads. `maxTotalInflatedBytes` counts the largest amount actually read from each distinct part during the lifetime of the loaded package; reading the same part again does not consume that budget twice. `maxArchiveEntries` bounds central-directory entries before the ZIP library allocates its owned index. Set an individual field to `null` to disable that configurable budget. Internal hard safety ceilings still apply, so disabling a budget does not make arbitrary archives acceptable. Values other than `null` must be positive safe integers; byte fields are expressed in bytes and the entry field is a count.
|
|
751
788
|
|
|
752
789
|
A violation rejects with `OoxmlResourceLimitError` (`code === 'ooxml-resource-limit'`). Its structured `details.violation` reports the resource, metric, limit, observed value, usage snapshot, and part name when a particular part caused the failure. The deprecated `maxZipEntryBytes` option remains as a compatibility alias for `resourceLimits.maxArchiveEntryBytes`, but is scheduled for removal in a future breaking release; new code should use `resourceLimits`.
|
|
753
790
|
|
|
@@ -769,6 +806,7 @@ await viewer.load(file);
|
|
|
769
806
|
resourceLimits: {
|
|
770
807
|
maxArchiveEntryBytes: 128 * 1024 * 1024,
|
|
771
808
|
maxTotalInflatedBytes: 256 * 1024 * 1024,
|
|
809
|
+
maxArchiveEntries: 4096,
|
|
772
810
|
},
|
|
773
811
|
});
|
|
774
812
|
```
|
|
@@ -781,7 +819,7 @@ await viewer.load(file);
|
|
|
781
819
|
The package counters and raster-image guards are deterministic admission limits, not exact JavaScript/WASM process-memory accounting. XML trees, document models, canvas backing stores, browser decoder overhead, renderer state, and browser-managed SVG/vector parse or decoded storage can still require several times the measured input. SVG has no portable decoded-byte measure or explicit browser release primitive; the library count-bounds its cache and revokes owned object URLs, but cannot charge it as RGBA bytes. The defaults therefore reduce risk but cannot promise that an OOM is impossible on every device. Running parse and render work in `mode: 'worker'` can contain many failures away from the main UI thread, but a Worker is not a separate operating-system process or a strict memory sandbox.
|
|
782
820
|
|
|
783
821
|
A measured limit crossing is reported as `OoxmlResourceLimitError`. A residual WASM failure that reaches a recognized trap-shaped boundary is reported conservatively as `parser-crashed`, not `parser-oom`: with the current aborting Rust/WASM boundary, panic, allocation failure, explicit `unreachable`, and stack overflow can lose their distinct causes and converge on the same generic runtime error. Inferring OOM from an exception class or message would misclassify some parser defects as large-file failures. Reliable OOM classification would require preserving a structured cause before the trap across every relevant allocation path; it cannot be recovered from the generic trap afterward. The WebAssembly JavaScript embedding also permits implementation-defined stack/OOM failures, including an indistinguishable plain `Error` or process termination, so converting and poisoning every engine-level failure cannot be guaranteed.
|
|
784
|
-
- **No network by default.** The library does not send telemetry or analytics, and does not contact third-party services unless you ask it to. In particular, theme webfonts, Office font metric substitutes (Carlito/Caladea), and the script fallback fonts are **not** loaded from Google Fonts unless you pass `useGoogleFonts: true` to the relevant `Viewer` / `load(...)` options — supported uniformly by `DocxViewer`, `PptxViewer`, and `
|
|
822
|
+
- **No network by default.** The library does not send telemetry or analytics, and does not contact third-party services unless you ask it to. In particular, theme webfonts, Office font metric substitutes (Carlito/Caladea), and the script fallback fonts are **not** loaded from Google Fonts unless you pass `useGoogleFonts: true` to the relevant `Viewer` / `load(...)` options — supported uniformly by `DocxViewer`, `PptxViewer`, `XlsxViewer`, and `XlsxSheetViewer`. When enabled, fonts for non-Latin scripts are supplied on demand from Noto families so text does not fall back to tofu: Arabic (Noto Naskh/Sans Arabic), CJK (Noto Sans/Serif KR · SC · TC · JP, picked per document language so shared Han glyphs take the right shapes), Cyrillic (Noto Sans/Serif), Hebrew (Noto Sans/Serif Hebrew, RTL), Thai (Noto Sans Thai) and Devanagari (Noto Sans Devanagari). No font binaries ship in the bundle. Enabling this option causes the end-user's browser to send an HTTP request (IP and User-Agent) to `fonts.googleapis.com`, which may have GDPR implications for your application — consider self-hosting the required fonts via `@font-face` instead.
|
|
785
823
|
- **XML parsing.** Uses `roxmltree`, which does not resolve external entities (XXE-safe by default).
|
|
786
824
|
- **Encrypted OOXML ([MS-OFFCRYPTO] Agile Encryption).** Password-protected `.docx` / `.xlsx` / `.pptx` files are OLE2/CFB containers, not ZIPs. Pass `password` to `load(...)` and the file is decrypted **client-side** via WebCrypto — no bytes and no password leave the browser:
|
|
787
825
|
```ts
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
//#region packages/core/src/fonts/font-registry.ts
|
|
2
|
+
var e = /* @__PURE__ */ new Map();
|
|
3
|
+
function t(t, n, r) {
|
|
4
|
+
let i = e.get(t), a = i?.get(n);
|
|
5
|
+
if (a) return a.refs++, {
|
|
6
|
+
face: a.face,
|
|
7
|
+
isNew: !1
|
|
8
|
+
};
|
|
9
|
+
let o = r(), s = i ?? /* @__PURE__ */ new Map();
|
|
10
|
+
return s.set(n, {
|
|
11
|
+
face: o,
|
|
12
|
+
set: n,
|
|
13
|
+
refs: 1
|
|
14
|
+
}), e.set(t, s), {
|
|
15
|
+
face: o,
|
|
16
|
+
isNew: !0
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function n(t) {
|
|
20
|
+
let n = /* @__PURE__ */ new Set();
|
|
21
|
+
for (let r of t) if (!n.has(r)) {
|
|
22
|
+
n.add(r);
|
|
23
|
+
for (let [t, n] of e) {
|
|
24
|
+
let i = !1;
|
|
25
|
+
for (let [a, o] of n) if (o.face === r) {
|
|
26
|
+
if (i = !0, o.refs--, o.refs <= 0) {
|
|
27
|
+
try {
|
|
28
|
+
o.set.delete(r);
|
|
29
|
+
} catch {}
|
|
30
|
+
n.delete(a), n.size === 0 && e.delete(t);
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
if (i) break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region packages/core/src/fonts/preload.ts
|
|
40
|
+
var r = 15e3;
|
|
41
|
+
function i(e) {
|
|
42
|
+
return Promise.race([e, new Promise((e) => setTimeout(e, r))]);
|
|
43
|
+
}
|
|
44
|
+
var a = /* @__PURE__ */ new Map();
|
|
45
|
+
function o(e) {
|
|
46
|
+
let t = [], n = /@font-face\s*\{([^}]*)\}/g, r;
|
|
47
|
+
for (; r = n.exec(e);) {
|
|
48
|
+
let e = r[1], n = (t) => e.match(RegExp(`(?:^|;|\\n)\\s*${t}\\s*:\\s*([^;]+)`, "i"))?.[1].trim(), i = n("font-family"), a = n("src");
|
|
49
|
+
if (!i || !a) continue;
|
|
50
|
+
let o = {}, s = n("font-style");
|
|
51
|
+
s && (o.style = s);
|
|
52
|
+
let c = n("font-weight");
|
|
53
|
+
c && (o.weight = c);
|
|
54
|
+
let l = n("font-stretch");
|
|
55
|
+
l && (o.stretch = l);
|
|
56
|
+
let u = n("unicode-range");
|
|
57
|
+
u && (o.unicodeRange = u), t.push({
|
|
58
|
+
family: i.replace(/^['"]|['"]$/g, ""),
|
|
59
|
+
src: a,
|
|
60
|
+
descriptors: o
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return t;
|
|
64
|
+
}
|
|
65
|
+
function s() {
|
|
66
|
+
return typeof document < "u" && document && document.fonts ? document.fonts : typeof self < "u" && self && "fonts" in self ? self.fonts : null;
|
|
67
|
+
}
|
|
68
|
+
function c(e, t) {
|
|
69
|
+
let n = t.descriptors;
|
|
70
|
+
return [
|
|
71
|
+
"gfonts",
|
|
72
|
+
e,
|
|
73
|
+
t.family.toLowerCase(),
|
|
74
|
+
n.style ?? "",
|
|
75
|
+
n.weight ?? "",
|
|
76
|
+
n.stretch ?? "",
|
|
77
|
+
n.unicodeRange ?? "",
|
|
78
|
+
t.src
|
|
79
|
+
].join("|");
|
|
80
|
+
}
|
|
81
|
+
async function l(e, n, r = s()) {
|
|
82
|
+
let l = r;
|
|
83
|
+
if (!l || typeof FontFace > "u" || typeof fetch > "u") return [];
|
|
84
|
+
let u = /* @__PURE__ */ new Set(), d = /* @__PURE__ */ new Set(), f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Set();
|
|
85
|
+
for (let t of e) {
|
|
86
|
+
if (!t) continue;
|
|
87
|
+
let e = t.toLowerCase();
|
|
88
|
+
if (u.has(e)) continue;
|
|
89
|
+
u.add(e);
|
|
90
|
+
let r = n[e];
|
|
91
|
+
if (!r) continue;
|
|
92
|
+
f.add(r.url);
|
|
93
|
+
let i = (r.loadFamily ?? t).toLowerCase();
|
|
94
|
+
d.add(i);
|
|
95
|
+
let a = p.get(r.url);
|
|
96
|
+
a || (a = /* @__PURE__ */ new Set(), p.set(r.url, a)), a.add(i);
|
|
97
|
+
}
|
|
98
|
+
if (d.size === 0) return [];
|
|
99
|
+
let h = await i(Promise.all([...f].map(async (e) => {
|
|
100
|
+
let t = a.get(e);
|
|
101
|
+
if (t) return {
|
|
102
|
+
url: e,
|
|
103
|
+
rules: await t
|
|
104
|
+
};
|
|
105
|
+
let n = (async () => {
|
|
106
|
+
try {
|
|
107
|
+
let t = await fetch(e);
|
|
108
|
+
if (!t.ok) throw Error(`HTTP ${t.status}`);
|
|
109
|
+
return o(await t.text());
|
|
110
|
+
} catch {
|
|
111
|
+
a.delete(e);
|
|
112
|
+
for (let t of p.get(e) ?? []) m.add(t);
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
})();
|
|
116
|
+
return a.set(e, n), {
|
|
117
|
+
url: e,
|
|
118
|
+
rules: await n
|
|
119
|
+
};
|
|
120
|
+
}))), g = [], _ = [];
|
|
121
|
+
for (let e of Array.isArray(h) ? h : []) for (let n of e.rules) {
|
|
122
|
+
let { face: r, isNew: i } = t(c(e.url, n), l, () => {
|
|
123
|
+
let e = new FontFace(n.family, n.src, n.descriptors);
|
|
124
|
+
return l.add(e), e;
|
|
125
|
+
});
|
|
126
|
+
g.push(r), i && _.push(r);
|
|
127
|
+
}
|
|
128
|
+
return _.length > 0 && await i(Promise.allSettled(_.map((e) => e.load())).then((e) => (e.forEach((e, t) => {
|
|
129
|
+
e.status === "rejected" && m.add(_[t].family.replace(/['"]/g, "").toLowerCase());
|
|
130
|
+
}), l.ready))), m.size > 0 && console.warn(`[ooxml] failed to preload web font(s): ${[...m].join(", ")}; falling back to system fonts (text may shift or differ).`), g;
|
|
131
|
+
}
|
|
132
|
+
function u(e) {
|
|
133
|
+
n(e);
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
//#region packages/core/src/internal/bounded-async-lru-cache.ts
|
|
137
|
+
function d(e, t) {
|
|
138
|
+
if (!Number.isSafeInteger(e) || e <= 0) throw TypeError(`${t} must be a positive safe integer`);
|
|
139
|
+
}
|
|
140
|
+
function f(e) {
|
|
141
|
+
if (!Number.isSafeInteger(e) || e < 0) throw TypeError("cache entry weight must be a non-negative safe integer");
|
|
142
|
+
}
|
|
143
|
+
var p = class {
|
|
144
|
+
#e;
|
|
145
|
+
#t;
|
|
146
|
+
#n;
|
|
147
|
+
#r;
|
|
148
|
+
#i = /* @__PURE__ */ new Map();
|
|
149
|
+
#a = /* @__PURE__ */ new Map();
|
|
150
|
+
#o = 0;
|
|
151
|
+
constructor(e) {
|
|
152
|
+
d(e.maxEntries, "maxEntries"), d(e.maxWeight, "maxWeight"), this.#e = e.maxEntries, this.#t = e.maxWeight, this.#n = e.measure, this.#r = e.onRemove;
|
|
153
|
+
}
|
|
154
|
+
get usage() {
|
|
155
|
+
return {
|
|
156
|
+
entries: this.#i.size,
|
|
157
|
+
weight: this.#o,
|
|
158
|
+
pending: this.#a.size
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
has(e) {
|
|
162
|
+
return this.#i.has(e);
|
|
163
|
+
}
|
|
164
|
+
get(e) {
|
|
165
|
+
let t = this.#i.get(e);
|
|
166
|
+
if (t !== void 0) return this.#i.delete(e), this.#i.set(e, t), t.value;
|
|
167
|
+
}
|
|
168
|
+
getOrLoad(e, t) {
|
|
169
|
+
let n = this.get(e);
|
|
170
|
+
if (n !== void 0 || this.#i.has(e)) return Promise.resolve(n);
|
|
171
|
+
let r = this.#a.get(e);
|
|
172
|
+
if (r !== void 0) return r.promise;
|
|
173
|
+
let i = {}, a = Promise.resolve().then(t).then((t) => this.#c(e, i, t), (t) => {
|
|
174
|
+
throw this.#s(e, i), t;
|
|
175
|
+
});
|
|
176
|
+
return this.#a.set(e, {
|
|
177
|
+
token: i,
|
|
178
|
+
promise: a
|
|
179
|
+
}), a;
|
|
180
|
+
}
|
|
181
|
+
delete(e) {
|
|
182
|
+
let t = this.#a.delete(e), n = this.#i.get(e);
|
|
183
|
+
return n === void 0 ? t : (this.#i.delete(e), this.#o -= n.weight, this.#l(n.value, e, "deleted"), !0);
|
|
184
|
+
}
|
|
185
|
+
clear() {
|
|
186
|
+
this.#a.clear();
|
|
187
|
+
let e = [...this.#i];
|
|
188
|
+
this.#i.clear(), this.#o = 0;
|
|
189
|
+
for (let [t, n] of e) this.#l(n.value, t, "cleared");
|
|
190
|
+
}
|
|
191
|
+
#s(e, t) {
|
|
192
|
+
this.#a.get(e)?.token === t && this.#a.delete(e);
|
|
193
|
+
}
|
|
194
|
+
#c(e, t, n) {
|
|
195
|
+
if (this.#a.get(e)?.token !== t) return n;
|
|
196
|
+
let r;
|
|
197
|
+
try {
|
|
198
|
+
r = this.#n(n), f(r);
|
|
199
|
+
} catch (n) {
|
|
200
|
+
throw this.#s(e, t), n;
|
|
201
|
+
}
|
|
202
|
+
if (this.#a.get(e)?.token !== t || (this.#a.delete(e), r > this.#t)) return n;
|
|
203
|
+
let i = [];
|
|
204
|
+
for (; this.#i.size >= this.#e || r > this.#t - this.#o;) {
|
|
205
|
+
let e = this.#i.entries().next().value;
|
|
206
|
+
if (e === void 0) break;
|
|
207
|
+
let [t, n] = e;
|
|
208
|
+
this.#i.delete(t), this.#o -= n.weight, i.push([t, n]);
|
|
209
|
+
}
|
|
210
|
+
this.#i.set(e, {
|
|
211
|
+
value: n,
|
|
212
|
+
weight: r
|
|
213
|
+
}), this.#o += r;
|
|
214
|
+
for (let [e, t] of i) this.#l(t.value, e, "evicted");
|
|
215
|
+
return n;
|
|
216
|
+
}
|
|
217
|
+
#l(e, t, n) {
|
|
218
|
+
try {
|
|
219
|
+
this.#r?.(e, t, n);
|
|
220
|
+
} catch {}
|
|
221
|
+
}
|
|
222
|
+
}, m = class {
|
|
223
|
+
#e;
|
|
224
|
+
constructor(e) {
|
|
225
|
+
this.#e = new p({
|
|
226
|
+
maxEntries: e.maxEntries,
|
|
227
|
+
maxWeight: e.maxBytes,
|
|
228
|
+
measure: (e) => e.size
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
get usage() {
|
|
232
|
+
let e = this.#e.usage;
|
|
233
|
+
return {
|
|
234
|
+
entries: e.entries,
|
|
235
|
+
bytes: e.weight,
|
|
236
|
+
pending: e.pending
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
async get(e, t, n) {
|
|
240
|
+
if (typeof e != "string" || e.length === 0) throw TypeError("raw package part path must be a non-empty string");
|
|
241
|
+
if (typeof t != "string") throw TypeError("raw package part MIME type must be a string");
|
|
242
|
+
let r = await this.#e.getOrLoad(e, async () => {
|
|
243
|
+
let e = await n();
|
|
244
|
+
if (!(e instanceof Blob)) throw TypeError("raw package part loader must return a Blob");
|
|
245
|
+
return e;
|
|
246
|
+
});
|
|
247
|
+
return t === "" || r.type === t ? r : r.slice(0, r.size, t);
|
|
248
|
+
}
|
|
249
|
+
clear() {
|
|
250
|
+
this.#e.clear();
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
//#endregion
|
|
254
|
+
export { u as a, t as c, l as i, p as n, i as o, s as r, n as s, m as t };
|