@webskill/sdk 0.27.1 → 0.28.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/dist/agent.d.ts +3 -3
- package/dist/agent.js +897 -115
- package/dist/{approval-BSwffz8P.js → approval-5BmspsRi.js} +1 -1
- package/dist/browser.d.ts +7 -7
- package/dist/browser.js +415 -49
- package/dist/governance.d.ts +3 -3
- package/dist/{index--GvzV6Lq.d.ts → index-CkauSvus.d.ts} +90 -5
- package/dist/{index-C8-9-8zo.d.ts → index-DJeYqzlE.d.ts} +41 -13
- package/dist/{index-D6eSrEi5.d.ts → index-DU8sKyQq.d.ts} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +10 -4
- package/dist/mcp.d.ts +2 -2
- package/dist/{miniChart-D0nYMzz8.js → miniChart-k95Dpy0q.js} +82 -4
- package/dist/node.d.ts +4 -3
- package/dist/node.js +18 -1
- package/dist/{openUiLibrary-CxtrnX54.js → openUiLibrary-BnhYUlqY.js} +1 -1
- package/dist/{openUiSpecLang-DIcLcybq.js → openUiSpecLang-C8qNOxzA.js} +432 -19
- package/dist/{renderResult-D9Q-Vu2x.js → renderResult-2v3WQzs_.js} +5 -2
- package/dist/{skillVersionStore-S4_HJ_Fl-Ds97pwm5.d.ts → skillVersionStore-S4_HJ_Fl-DzZM_UIw.d.ts} +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/{types-CpDRZ0rA-CFQ-vdKz.d.ts → types-wKp3YBSM-167azx1H.d.ts} +6 -2
- package/dist/ui-react.d.ts +3 -3
- package/dist/ui-react.js +39 -3
- package/dist/ui-vue.d.ts +1 -1
- package/dist/ui-vue.js +1 -1
- package/dist/ui.d.ts +4 -4
- package/dist/ui.js +13 -7
- package/dist/{webSkillApi-C_7CTwtB.js → webSkillApi-rX2e3SVB.js} +1 -1
- package/dist/{webskillLitCatalog-BPyjYuRT.js → webskillLitCatalog-MfiLE5aq.js} +41 -2
- package/package.json +2 -1
|
@@ -5,7 +5,7 @@ import { t as assertRemoteUrlAllowed } from "./urlSafety-CiSuCJvX.js";
|
|
|
5
5
|
import { c as findUnpairedToolCalls, d as partsToText, f as promptText, l as interruptedToolResult, p as textParts, u as sealToolCallPairs } from "./llm-eIQNO9tr.js";
|
|
6
6
|
import { a as UNSUPPORTED_DOCUMENT_MESSAGE, c as toBase64, f as SPREADSHEET_MIME_TYPE, g as DEFAULT_MAX_DOCUMENT_TEXT_BYTES, h as DEFAULT_MAX_DOCUMENT_BYTES, i as SUPPORTED_DOCUMENT_MIME, l as encodeSpreadsheet, n as READ_LINKED_DOCUMENT_TOOL, o as fromBase64, r as READ_LINKED_DOCUMENT_TOOL_NAME, s as isBytesOnlyDocument, v as TEXT_BUDGETED_CONTENT_TYPES } from "./linkedDocument-0iiVPd5t.js";
|
|
7
7
|
import { t as mergeCatalogEntries } from "./external-_ZRQe-V9.js";
|
|
8
|
-
import { i as isArtifactCardHidden, n as extractChartSpec, r as admitArtifactMetadata, t as buildRenderResult } from "./renderResult-
|
|
8
|
+
import { i as isArtifactCardHidden, n as extractChartSpec, r as admitArtifactMetadata, t as buildRenderResult } from "./renderResult-2v3WQzs_.js";
|
|
9
9
|
import { t as extractUiSpecEvents } from "./surface-DVGiCmwq.js";
|
|
10
10
|
import { t as MemoryArtifactStore } from "./memoryArtifactStore-Bs7glPqm.js";
|
|
11
11
|
|
package/dist/browser.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { G as FileStat, It as VerifyResult, K as FileSystemProvider, Lt as WebSkillError, N as ArchiveLimits, Ot as SkillsLockfile, Pt as UnsignedPolicy, S as UiBridge, St as SkillManifest, b as RenderResultRequest, c as InteractionResponse, jt as TrustedKeyStore, l as LlmClient, m as LlmStreamEvent, o as InteractionPolicy, p as LlmResponse, q as FileWriteStream, s as InteractionRequest, u as LlmCompleteInput, v as MemoryStore, vt as SkillInstallSource } from "./types-
|
|
2
|
-
import { $ as ImageOmission, B as ExternalToolSource, C as BridgeResponse, N as DocumentSurfaceHost, Pn as ToolResult, S as BridgeRequest, Sr as bridgeError, Yr as parseBridgeRequest, b as BridgeCapabilities, ct as LinkedDocumentReader, en as ScriptExecutionContext, jn as ToolDefinition, m as ApprovalScope, mr as WebSkillApi, sr as ViewerImageFact, tn as ScriptExecutor, ut as NetworkPolicy, z as ExternalSkillProvider } from "./index-
|
|
3
|
-
import {
|
|
1
|
+
import { G as FileStat, It as VerifyResult, K as FileSystemProvider, Lt as WebSkillError, N as ArchiveLimits, Ot as SkillsLockfile, Pt as UnsignedPolicy, S as UiBridge, St as SkillManifest, b as RenderResultRequest, c as InteractionResponse, jt as TrustedKeyStore, l as LlmClient, m as LlmStreamEvent, o as InteractionPolicy, p as LlmResponse, q as FileWriteStream, s as InteractionRequest, u as LlmCompleteInput, v as MemoryStore, vt as SkillInstallSource } from "./types-wKp3YBSM-167azx1H.js";
|
|
2
|
+
import { $ as ImageOmission, B as ExternalToolSource, C as BridgeResponse, N as DocumentSurfaceHost, Pn as ToolResult, S as BridgeRequest, Sr as bridgeError, Yr as parseBridgeRequest, b as BridgeCapabilities, ct as LinkedDocumentReader, en as ScriptExecutionContext, jn as ToolDefinition, m as ApprovalScope, mr as WebSkillApi, sr as ViewerImageFact, tn as ScriptExecutor, ut as NetworkPolicy, z as ExternalSkillProvider } from "./index-DU8sKyQq.js";
|
|
3
|
+
import { In as PerceptionScopeInput, K as DocxDocumentContent, Ln as PptxDocumentContent, Pn as PerceptionResult, Rn as PptxDocumentReader, Tn as PdfDocumentReader, Ut as NestedFrameRef, cn as PageActionRequest, dn as PageActionTarget, ii as XlsxDocumentReader, in as PageActionOutcome, jn as PerceptionCaptureOptions, kn as PerceivedNode, mn as PageAuditSink, nn as PageActionExecutor, q as DocxDocumentReader, ri as XlsxDocumentContent, si as XlsxTableReader, u as ConsentUi, un as PageActionScopeInput, xn as PagePerceptionReader, yn as PagePerceptionPolicy, yr as SubtreeRejection } from "./index-CkauSvus.js";
|
|
4
4
|
//#region ../browser/dist/index.d.ts
|
|
5
5
|
//#region src/fs/featureDetection.d.ts
|
|
6
6
|
/** 检测当前环境是否可用 OPFS(navigator.storage.getDirectory) */
|
|
@@ -18,6 +18,7 @@ declare class OpfsProvider implements FileSystemProvider {
|
|
|
18
18
|
writeText(p: string, content: string): Promise<void>;
|
|
19
19
|
appendText(p: string, content: string): Promise<void>;
|
|
20
20
|
readBinary(p: string): Promise<Uint8Array>;
|
|
21
|
+
createReadStream(p: string): Promise<AsyncIterable<Uint8Array>>;
|
|
21
22
|
writeBinary(p: string, content: Uint8Array): Promise<void>;
|
|
22
23
|
/**
|
|
23
24
|
* 分块写入(FR-18.2c)。`createWritable()` 本身就是写 swap 文件、`close()` 才提交,
|
|
@@ -1650,11 +1651,10 @@ declare function readXlsxBlocks(bytes: Uint8Array): Promise<XlsxDocumentContent>
|
|
|
1650
1651
|
//#endregion
|
|
1651
1652
|
//#region src/document/xlsxTable.d.ts
|
|
1652
1653
|
/**
|
|
1653
|
-
* xlsx →
|
|
1654
|
+
* xlsx → 单元格网格或可重复扫描的行流。
|
|
1654
1655
|
*
|
|
1655
|
-
*
|
|
1656
|
-
*
|
|
1657
|
-
* 错误语义同 `extractXlsxText`:旧版 `.xls`、归档损坏、缺 `xl/workbook.xml` 都抛 `WebSkillError`。
|
|
1656
|
+
* `read` 保留既有网格契约;`readStreaming` 用 SAX 逐行解析工作表,不受整包解压的 64 MiB 条目上限约束。
|
|
1657
|
+
* 两条路径使用同一套单元格取值、日期换算与空格补位规则,错误均带 `WebSkillError`。
|
|
1658
1658
|
* @experimental
|
|
1659
1659
|
*/
|
|
1660
1660
|
declare function createXlsxTableReader(): XlsxTableReader;
|
package/dist/browser.js
CHANGED
|
@@ -3,13 +3,14 @@ import { A as SKILL_MANIFEST_FILE, D as verifySkillSignature, M as buildManifest
|
|
|
3
3
|
import { o as atomicWriteText, r as resolveInsideRoot, s as isAtomicTempPath } from "./pathSecurity-CirkQwWP.js";
|
|
4
4
|
import { t as assertRemoteUrlAllowed } from "./urlSafety-CiSuCJvX.js";
|
|
5
5
|
import { t as ATTACHMENT_TEXT_LIMIT } from "./kind-Dc8x0HWz.js";
|
|
6
|
-
import { _ as FsRunSnapshotStore, a as networkPolicyLibSource, c as bridgeError, ct as ProgressiveRouter, d as FsMemoryStore, l as parseBridgeRequest, m as AgentLoop, r as normalizeToolError, s as UPLOAD_FILES_UNAVAILABLE, t as CapabilityApproval, u as FsArtifactStore } from "./approval-
|
|
6
|
+
import { _ as FsRunSnapshotStore, a as networkPolicyLibSource, c as bridgeError, ct as ProgressiveRouter, d as FsMemoryStore, l as parseBridgeRequest, m as AgentLoop, r as normalizeToolError, s as UPLOAD_FILES_UNAVAILABLE, t as CapabilityApproval, u as FsArtifactStore } from "./approval-5BmspsRi.js";
|
|
7
7
|
import { a as GoogleGenAiClient, o as AnthropicClient, s as OpenAiCompatibleClient, t as MockLlmClient } from "./llm-eIQNO9tr.js";
|
|
8
8
|
import { c as toBase64$1, f as SPREADSHEET_MIME_TYPE } from "./linkedDocument-0iiVPd5t.js";
|
|
9
9
|
import { n as normalizeToolContent, t as mergeCatalogEntries } from "./external-_ZRQe-V9.js";
|
|
10
|
-
import { t as createWebSkillApi } from "./webSkillApi-
|
|
10
|
+
import { t as createWebSkillApi } from "./webSkillApi-rX2e3SVB.js";
|
|
11
11
|
import { A as frameSteps, D as SCROLL_DIRECTIONS, E as toActionFrameScopes, O as toFrameScopes, _ as defersImage, a as columnWidthToPixels, b as isPdfTextTrustworthy, c as isRangeTopLeft, d as rangeContains, f as readImageSize, k as frameLabel, l as parseCellAddress, n as EMU_PER_POINT, o as fitWithin, p as PDF_LARGE_IMAGE_RATIO, r as EMU_PER_TWIP$1, s as formatCellAddress, t as EMU_PER_PIXEL, u as parseCellRange, v as takesImage } from "./geometry-BXMPNuM6.js";
|
|
12
|
-
import { zipSync } from "fflate";
|
|
12
|
+
import { Unzip, UnzipInflate, zipSync } from "fflate";
|
|
13
|
+
import { SaxesParser } from "saxes";
|
|
13
14
|
|
|
14
15
|
//#region ../browser/src/fs/featureDetection.ts
|
|
15
16
|
/** 检测当前环境是否可用 OPFS(navigator.storage.getDirectory) */
|
|
@@ -98,6 +99,21 @@ var OpfsProvider = class {
|
|
|
98
99
|
return new Uint8Array(await (await handle.getFile()).arrayBuffer());
|
|
99
100
|
});
|
|
100
101
|
}
|
|
102
|
+
async createReadStream(p) {
|
|
103
|
+
const stream = (await this.#wrap(p, async () => (await this.#walkFile(p)).getFile())).stream();
|
|
104
|
+
return (async function* () {
|
|
105
|
+
const reader = stream.getReader();
|
|
106
|
+
try {
|
|
107
|
+
for (;;) {
|
|
108
|
+
const { done, value } = await reader.read();
|
|
109
|
+
if (done) return;
|
|
110
|
+
if (value !== void 0) yield value;
|
|
111
|
+
}
|
|
112
|
+
} finally {
|
|
113
|
+
reader.releaseLock();
|
|
114
|
+
}
|
|
115
|
+
})();
|
|
116
|
+
}
|
|
101
117
|
async writeBinary(p, content) {
|
|
102
118
|
await this.#wrap(p, async () => {
|
|
103
119
|
const segments = this.#segments(p);
|
|
@@ -6437,12 +6453,12 @@ const XLSX_UNEXTRACTED = [
|
|
|
6437
6453
|
"hidden row and column marking",
|
|
6438
6454
|
"formula expressions (only cached values are read)"
|
|
6439
6455
|
];
|
|
6440
|
-
const WORKBOOK = "xl/workbook.xml";
|
|
6441
|
-
const WORKBOOK_RELS = "xl/_rels/workbook.xml.rels";
|
|
6442
|
-
const SHARED_STRINGS = "xl/sharedStrings.xml";
|
|
6443
|
-
const STYLES = "xl/styles.xml";
|
|
6456
|
+
const WORKBOOK$1 = "xl/workbook.xml";
|
|
6457
|
+
const WORKBOOK_RELS$1 = "xl/_rels/workbook.xml.rels";
|
|
6458
|
+
const SHARED_STRINGS$1 = "xl/sharedStrings.xml";
|
|
6459
|
+
const STYLES$1 = "xl/styles.xml";
|
|
6444
6460
|
/** OLE2 复合文档签名:旧版 .xls 的开头,它不是 zip,走不到解压那一步 */
|
|
6445
|
-
const OLE2_SIGNATURE = [
|
|
6461
|
+
const OLE2_SIGNATURE$1 = [
|
|
6446
6462
|
208,
|
|
6447
6463
|
207,
|
|
6448
6464
|
17,
|
|
@@ -6467,14 +6483,14 @@ const BUILTIN_DATE_FORMATS = /* @__PURE__ */ new Set([
|
|
|
6467
6483
|
46,
|
|
6468
6484
|
47
|
|
6469
6485
|
]);
|
|
6470
|
-
function fail(message) {
|
|
6486
|
+
function fail$1(message) {
|
|
6471
6487
|
throw new WebSkillError("TOOL_EXECUTION_FAILED", message);
|
|
6472
6488
|
}
|
|
6473
6489
|
/** 按 localName 取子孙元素,忽略命名空间前缀:不同生成器的前缀写法并不统一 */
|
|
6474
|
-
const byTag$
|
|
6475
|
-
function parseXml$
|
|
6490
|
+
const byTag$4 = (scope, name) => [...scope.getElementsByTagNameNS("*", name)];
|
|
6491
|
+
function parseXml$4(bytes, what) {
|
|
6476
6492
|
const doc = new DOMParser().parseFromString(new TextDecoder().decode(bytes), "application/xml");
|
|
6477
|
-
if (doc.getElementsByTagName("parsererror").length > 0) fail(`The workbook ${what} could not be parsed as XML.`);
|
|
6493
|
+
if (doc.getElementsByTagName("parsererror").length > 0) fail$1(`The workbook ${what} could not be parsed as XML.`);
|
|
6478
6494
|
return doc;
|
|
6479
6495
|
}
|
|
6480
6496
|
/** `B` → 1、`AA` → 26;拿不到列号时返回 undefined,由调用方顺位补上 */
|
|
@@ -6519,14 +6535,14 @@ function isDateFormatCode(code) {
|
|
|
6519
6535
|
/** 单元格样式索引 → 是否日期格式 */
|
|
6520
6536
|
function readDateStyles(bytes) {
|
|
6521
6537
|
if (bytes === void 0) return [];
|
|
6522
|
-
const doc = parseXml$
|
|
6538
|
+
const doc = parseXml$4(bytes, "styles");
|
|
6523
6539
|
const custom = /* @__PURE__ */ new Map();
|
|
6524
|
-
for (const fmt of byTag$
|
|
6540
|
+
for (const fmt of byTag$4(doc, "numFmt")) {
|
|
6525
6541
|
const id = Number(fmt.getAttribute("numFmtId"));
|
|
6526
6542
|
const code = fmt.getAttribute("formatCode");
|
|
6527
6543
|
if (Number.isFinite(id) && code !== null) custom.set(id, code);
|
|
6528
6544
|
}
|
|
6529
|
-
const cellXfs = byTag$
|
|
6545
|
+
const cellXfs = byTag$4(doc, "cellXfs")[0];
|
|
6530
6546
|
if (cellXfs === void 0) return [];
|
|
6531
6547
|
return [...cellXfs.children].filter((xf) => xf.localName === "xf").map((xf) => {
|
|
6532
6548
|
const id = Number(xf.getAttribute("numFmtId") ?? "0");
|
|
@@ -6591,7 +6607,7 @@ function cellText$1(cell, shared, dateStyles, date1904) {
|
|
|
6591
6607
|
function sheetRows(doc, shared, dateStyles, date1904) {
|
|
6592
6608
|
const rows = [];
|
|
6593
6609
|
let previousRow = 0;
|
|
6594
|
-
for (const row of byTag$
|
|
6610
|
+
for (const row of byTag$4(doc, "row")) {
|
|
6595
6611
|
const declared = Number(row.getAttribute("r"));
|
|
6596
6612
|
const rowNumber = Number.isInteger(declared) && declared > 0 ? declared : previousRow + 1;
|
|
6597
6613
|
for (let gap = previousRow + 1; gap < rowNumber; gap++) rows.push([]);
|
|
@@ -6614,9 +6630,9 @@ function sheetRows(doc, shared, dateStyles, date1904) {
|
|
|
6614
6630
|
}
|
|
6615
6631
|
/** 一行的文本:单元格用制表符分隔(与 docx 的表格同口径),行尾制表符不留 */
|
|
6616
6632
|
const rowLine = (cells) => cells.join(" ").replace(/\t+$/, "");
|
|
6617
|
-
const looksLikeOle2 = (bytes) => bytes.length >= OLE2_SIGNATURE.length && OLE2_SIGNATURE.every((byte, i) => bytes[i] === byte);
|
|
6633
|
+
const looksLikeOle2 = (bytes) => bytes.length >= OLE2_SIGNATURE$1.length && OLE2_SIGNATURE$1.every((byte, i) => bytes[i] === byte);
|
|
6618
6634
|
/** rels 里的 Target 可能是相对 `xl/` 的,也可能是包根绝对路径 */
|
|
6619
|
-
function resolveSheetPath(target) {
|
|
6635
|
+
function resolveSheetPath$1(target) {
|
|
6620
6636
|
const clean = target.replace(/^\.\//, "");
|
|
6621
6637
|
return clean.startsWith("/") ? clean.slice(1) : `xl/${clean}`;
|
|
6622
6638
|
}
|
|
@@ -6626,37 +6642,37 @@ function resolveSheetPath(target) {
|
|
|
6626
6642
|
* @throws WebSkillError 归档损坏、旧版 `.xls`、缺 `xl/workbook.xml`、工作表关系解不开、XML 解析失败
|
|
6627
6643
|
*/
|
|
6628
6644
|
async function readXlsxWorkbook(bytes) {
|
|
6629
|
-
if (looksLikeOle2(bytes)) fail("This is a legacy .xls workbook, which is not supported. Save it as .xlsx and try again.");
|
|
6645
|
+
if (looksLikeOle2(bytes)) fail$1("This is a legacy .xls workbook, which is not supported. Save it as .xlsx and try again.");
|
|
6630
6646
|
let entries;
|
|
6631
6647
|
try {
|
|
6632
6648
|
entries = await unzipWithLimits(bytes);
|
|
6633
6649
|
} catch {
|
|
6634
|
-
fail("This file could not be read as an Excel workbook: the archive is damaged or not a .xlsx file.");
|
|
6650
|
+
fail$1("This file could not be read as an Excel workbook: the archive is damaged or not a .xlsx file.");
|
|
6635
6651
|
}
|
|
6636
6652
|
const parts = new Map(entries);
|
|
6637
|
-
const workbookBytes = parts.get(WORKBOOK);
|
|
6638
|
-
if (workbookBytes === void 0) fail(`This file is not an Excel workbook: it has no ${WORKBOOK} entry.`);
|
|
6639
|
-
const workbook = parseXml$
|
|
6640
|
-
const workbookPr = byTag$
|
|
6653
|
+
const workbookBytes = parts.get(WORKBOOK$1);
|
|
6654
|
+
if (workbookBytes === void 0) fail$1(`This file is not an Excel workbook: it has no ${WORKBOOK$1} entry.`);
|
|
6655
|
+
const workbook = parseXml$4(workbookBytes, "index");
|
|
6656
|
+
const workbookPr = byTag$4(workbook, "workbookPr")[0];
|
|
6641
6657
|
const date1904 = workbookPr?.getAttribute("date1904") === "1" || workbookPr?.getAttribute("date1904") === "true";
|
|
6642
|
-
const relsBytes = parts.get(WORKBOOK_RELS);
|
|
6658
|
+
const relsBytes = parts.get(WORKBOOK_RELS$1);
|
|
6643
6659
|
const targets = /* @__PURE__ */ new Map();
|
|
6644
|
-
if (relsBytes !== void 0) for (const rel of byTag$
|
|
6660
|
+
if (relsBytes !== void 0) for (const rel of byTag$4(parseXml$4(relsBytes, "relationships"), "Relationship")) {
|
|
6645
6661
|
const id = rel.getAttribute("Id");
|
|
6646
6662
|
const target = rel.getAttribute("Target");
|
|
6647
|
-
if (id !== null && target !== null) targets.set(id, resolveSheetPath(target));
|
|
6663
|
+
if (id !== null && target !== null) targets.set(id, resolveSheetPath$1(target));
|
|
6648
6664
|
}
|
|
6649
|
-
const sharedBytes = parts.get(SHARED_STRINGS);
|
|
6650
|
-
const shared = sharedBytes === void 0 ? [] : byTag$
|
|
6651
|
-
const dateStyles = readDateStyles(parts.get(STYLES));
|
|
6665
|
+
const sharedBytes = parts.get(SHARED_STRINGS$1);
|
|
6666
|
+
const shared = sharedBytes === void 0 ? [] : byTag$4(parseXml$4(sharedBytes, "shared strings"), "si").map(sharedStringText);
|
|
6667
|
+
const dateStyles = readDateStyles(parts.get(STYLES$1));
|
|
6652
6668
|
const sheets = [];
|
|
6653
|
-
for (const [ordinal, sheet] of byTag$
|
|
6669
|
+
for (const [ordinal, sheet] of byTag$4(workbook, "sheet").entries()) {
|
|
6654
6670
|
const name = sheet.getAttribute("name") ?? `Sheet${ordinal + 1}`;
|
|
6655
6671
|
const relId = sheet.getAttributeNS("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id") ?? sheet.getAttribute("r:id");
|
|
6656
6672
|
const path = relId !== null ? targets.get(relId) : void 0;
|
|
6657
6673
|
const sheetBytes = path !== void 0 ? parts.get(path) : void 0;
|
|
6658
|
-
if (path === void 0 || sheetBytes === void 0) fail(`The worksheet "${name}" could not be located inside the workbook.`);
|
|
6659
|
-
const rows = sheetRows(parseXml$
|
|
6674
|
+
if (path === void 0 || sheetBytes === void 0) fail$1(`The worksheet "${name}" could not be located inside the workbook.`);
|
|
6675
|
+
const rows = sheetRows(parseXml$4(sheetBytes, `worksheet "${name}"`), shared, dateStyles, date1904);
|
|
6660
6676
|
const lines = rows.map(rowLine);
|
|
6661
6677
|
while (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
6662
6678
|
lines.pop();
|
|
@@ -6738,7 +6754,7 @@ const DEFAULT_BODY_TWIPS = 9360;
|
|
|
6738
6754
|
function attr(node, name) {
|
|
6739
6755
|
for (const item of node.attributes) if (item.name === name || item.localName === name) return item.value;
|
|
6740
6756
|
}
|
|
6741
|
-
function parseXml$
|
|
6757
|
+
function parseXml$3(bytes, what) {
|
|
6742
6758
|
const doc = new DOMParser().parseFromString(new TextDecoder().decode(bytes), "application/xml");
|
|
6743
6759
|
if (doc.getElementsByTagName("parsererror").length > 0) throw new WebSkillError("TOOL_EXECUTION_FAILED", `The Word document's ${what} could not be parsed as XML.`);
|
|
6744
6760
|
return doc;
|
|
@@ -6801,10 +6817,10 @@ async function readDocxBlocks(bytes) {
|
|
|
6801
6817
|
const files = new Map(entries);
|
|
6802
6818
|
const main = files.get(DOCUMENT$1);
|
|
6803
6819
|
if (main === void 0) throw new WebSkillError("TOOL_EXECUTION_FAILED", `This file is not a Word document: it has no ${DOCUMENT$1} entry.`);
|
|
6804
|
-
const doc = parseXml$
|
|
6820
|
+
const doc = parseXml$3(main, "body");
|
|
6805
6821
|
const targets = /* @__PURE__ */ new Map();
|
|
6806
6822
|
const rels = files.get(RELS);
|
|
6807
|
-
if (rels !== void 0) for (const rel of parseXml$
|
|
6823
|
+
if (rels !== void 0) for (const rel of parseXml$3(rels, "relationships").getElementsByTagName("Relationship")) {
|
|
6808
6824
|
const id = attr(rel, "Id");
|
|
6809
6825
|
const target = attr(rel, "Target");
|
|
6810
6826
|
if (id !== void 0 && target !== void 0) targets.set(id, `word/${target.replace(/^\.?\//, "")}`);
|
|
@@ -6853,8 +6869,8 @@ const ANCHOR_TAGS = /* @__PURE__ */ new Set([
|
|
|
6853
6869
|
/** 绝对锚点没有行号;放在表尾,保证图片不丢。 */
|
|
6854
6870
|
const AFTER_LAST_ROW = Number.MAX_SAFE_INTEGER;
|
|
6855
6871
|
const RELATIONSHIPS_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
6856
|
-
const byTag$
|
|
6857
|
-
function parseXml$
|
|
6872
|
+
const byTag$3 = (scope, name) => [...scope.getElementsByTagNameNS("*", name)];
|
|
6873
|
+
function parseXml$2(bytes) {
|
|
6858
6874
|
const doc = new DOMParser().parseFromString(new TextDecoder().decode(bytes), "application/xml");
|
|
6859
6875
|
return doc.getElementsByTagName("parsererror").length > 0 ? void 0 : doc;
|
|
6860
6876
|
}
|
|
@@ -6875,9 +6891,9 @@ const relsOf = (path) => `${dirOf(path)}_rels/${path.slice(path.lastIndexOf("/")
|
|
|
6875
6891
|
function readRels(parts, path) {
|
|
6876
6892
|
const out = /* @__PURE__ */ new Map();
|
|
6877
6893
|
const bytes = parts.get(relsOf(path));
|
|
6878
|
-
const doc = bytes === void 0 ? void 0 : parseXml$
|
|
6894
|
+
const doc = bytes === void 0 ? void 0 : parseXml$2(bytes);
|
|
6879
6895
|
if (doc === void 0) return out;
|
|
6880
|
-
for (const rel of byTag$
|
|
6896
|
+
for (const rel of byTag$3(doc, "Relationship")) {
|
|
6881
6897
|
const id = rel.getAttribute("Id");
|
|
6882
6898
|
const target = rel.getAttribute("Target");
|
|
6883
6899
|
if (id !== null && target !== null) out.set(id, resolveRelative$1(dirOf(path), target));
|
|
@@ -6885,7 +6901,7 @@ function readRels(parts, path) {
|
|
|
6885
6901
|
return out;
|
|
6886
6902
|
}
|
|
6887
6903
|
const anchorNumber = (anchor, name) => {
|
|
6888
|
-
const node = anchor === void 0 ? void 0 : byTag$
|
|
6904
|
+
const node = anchor === void 0 ? void 0 : byTag$3(anchor, name)[0];
|
|
6889
6905
|
const value = Number(node?.textContent ?? NaN);
|
|
6890
6906
|
return Number.isInteger(value) && value >= 0 ? value : 0;
|
|
6891
6907
|
};
|
|
@@ -6902,14 +6918,14 @@ function imagesOf(parts, sheetPath) {
|
|
|
6902
6918
|
for (const [, target] of sheetRels) {
|
|
6903
6919
|
if (!target.includes("/drawings/")) continue;
|
|
6904
6920
|
const drawingBytes = parts.get(target);
|
|
6905
|
-
const drawing = drawingBytes === void 0 ? void 0 : parseXml$
|
|
6921
|
+
const drawing = drawingBytes === void 0 ? void 0 : parseXml$2(drawingBytes);
|
|
6906
6922
|
if (drawing === void 0) continue;
|
|
6907
6923
|
const drawingRels = readRels(parts, target);
|
|
6908
6924
|
const anchors = [...drawing.documentElement?.children ?? []].filter((element) => ANCHOR_TAGS.has(element.localName));
|
|
6909
6925
|
for (const anchor of anchors) {
|
|
6910
|
-
const from = byTag$
|
|
6926
|
+
const from = byTag$3(anchor, "from")[0];
|
|
6911
6927
|
const row = anchor.localName === "absoluteAnchor" || from === void 0 ? AFTER_LAST_ROW : anchorNumber(from, "row");
|
|
6912
|
-
const blip = byTag$
|
|
6928
|
+
const blip = byTag$3(anchor, "blip")[0];
|
|
6913
6929
|
const relId = blip?.getAttributeNS(RELATIONSHIPS_NS, "embed") ?? blip?.getAttribute("r:embed");
|
|
6914
6930
|
const path = relId === null || relId === void 0 ? void 0 : drawingRels.get(relId);
|
|
6915
6931
|
const data = path === void 0 ? void 0 : parts.get(path);
|
|
@@ -6951,18 +6967,368 @@ async function readXlsxBlocks(bytes) {
|
|
|
6951
6967
|
return { sheets: out };
|
|
6952
6968
|
}
|
|
6953
6969
|
|
|
6970
|
+
//#endregion
|
|
6971
|
+
//#region ../browser/src/document/xlsxStreaming.ts
|
|
6972
|
+
const WORKBOOK = "xl/workbook.xml";
|
|
6973
|
+
const WORKBOOK_RELS = "xl/_rels/workbook.xml.rels";
|
|
6974
|
+
const SHARED_STRINGS = "xl/sharedStrings.xml";
|
|
6975
|
+
const STYLES = "xl/styles.xml";
|
|
6976
|
+
const OLE2_SIGNATURE = [
|
|
6977
|
+
208,
|
|
6978
|
+
207,
|
|
6979
|
+
17,
|
|
6980
|
+
224,
|
|
6981
|
+
161,
|
|
6982
|
+
177,
|
|
6983
|
+
26,
|
|
6984
|
+
225
|
|
6985
|
+
];
|
|
6986
|
+
function fail(message) {
|
|
6987
|
+
throw new WebSkillError("TOOL_EXECUTION_FAILED", message);
|
|
6988
|
+
}
|
|
6989
|
+
async function sourceChunks(source) {
|
|
6990
|
+
if (typeof source !== "function") return (async function* () {
|
|
6991
|
+
yield source;
|
|
6992
|
+
})();
|
|
6993
|
+
return await source();
|
|
6994
|
+
}
|
|
6995
|
+
async function* entryChunks(source, path, state) {
|
|
6996
|
+
const output = [];
|
|
6997
|
+
let failure;
|
|
6998
|
+
const unzip = new Unzip();
|
|
6999
|
+
unzip.register(UnzipInflate);
|
|
7000
|
+
unzip.onfile = (file) => {
|
|
7001
|
+
if (file.name !== path) return;
|
|
7002
|
+
state.found = true;
|
|
7003
|
+
file.ondata = (error, chunk) => {
|
|
7004
|
+
if (error !== null) failure = error;
|
|
7005
|
+
else if (failure === void 0) output.push(chunk);
|
|
7006
|
+
};
|
|
7007
|
+
file.start();
|
|
7008
|
+
};
|
|
7009
|
+
try {
|
|
7010
|
+
const chunks = await sourceChunks(source);
|
|
7011
|
+
for await (const chunk of chunks) {
|
|
7012
|
+
unzip.push(chunk, false);
|
|
7013
|
+
yield* output.splice(0);
|
|
7014
|
+
await Promise.resolve();
|
|
7015
|
+
yield* output.splice(0);
|
|
7016
|
+
}
|
|
7017
|
+
unzip.push(/* @__PURE__ */ new Uint8Array(), true);
|
|
7018
|
+
await Promise.resolve();
|
|
7019
|
+
yield* output.splice(0);
|
|
7020
|
+
} catch (e) {
|
|
7021
|
+
failure ??= e;
|
|
7022
|
+
}
|
|
7023
|
+
if (failure !== void 0) {
|
|
7024
|
+
if (failure instanceof WebSkillError) throw failure;
|
|
7025
|
+
throw new WebSkillError("TOOL_EXECUTION_FAILED", `The workbook entry "${path}" could not be read: ${failure instanceof Error ? failure.message : String(failure)}`, failure);
|
|
7026
|
+
}
|
|
7027
|
+
}
|
|
7028
|
+
async function entryBytes(source, path) {
|
|
7029
|
+
const chunks = [];
|
|
7030
|
+
let total = 0;
|
|
7031
|
+
const state = { found: false };
|
|
7032
|
+
for await (const chunk of entryChunks(source, path, state)) {
|
|
7033
|
+
chunks.push(chunk);
|
|
7034
|
+
total += chunk.byteLength;
|
|
7035
|
+
}
|
|
7036
|
+
if (!state.found) return void 0;
|
|
7037
|
+
const out = new Uint8Array(total);
|
|
7038
|
+
let offset = 0;
|
|
7039
|
+
for (const chunk of chunks) {
|
|
7040
|
+
out.set(chunk, offset);
|
|
7041
|
+
offset += chunk.byteLength;
|
|
7042
|
+
}
|
|
7043
|
+
return out;
|
|
7044
|
+
}
|
|
7045
|
+
function parseXml$1(bytes, what) {
|
|
7046
|
+
const doc = new DOMParser().parseFromString(new TextDecoder().decode(bytes), "application/xml");
|
|
7047
|
+
if (doc.getElementsByTagName("parsererror").length > 0) fail(`The workbook ${what} could not be parsed as XML.`);
|
|
7048
|
+
return doc;
|
|
7049
|
+
}
|
|
7050
|
+
const byTag$2 = (scope, name) => [...scope.getElementsByTagNameNS("*", name)];
|
|
7051
|
+
const localName = (value) => {
|
|
7052
|
+
const name = typeof value === "string" ? value : value.name;
|
|
7053
|
+
return name.slice(name.lastIndexOf(":") + 1);
|
|
7054
|
+
};
|
|
7055
|
+
function attribute(tag, name) {
|
|
7056
|
+
const direct = tag.attributes[name];
|
|
7057
|
+
if (direct !== void 0) return direct;
|
|
7058
|
+
const key = Object.keys(tag.attributes).find((candidate) => candidate.endsWith(`:${name}`));
|
|
7059
|
+
return key === void 0 ? null : tag.attributes[key] ?? null;
|
|
7060
|
+
}
|
|
7061
|
+
function newParser(onError) {
|
|
7062
|
+
const parser = new SaxesParser();
|
|
7063
|
+
parser.on("error", onError);
|
|
7064
|
+
return parser;
|
|
7065
|
+
}
|
|
7066
|
+
async function readSharedStrings(source) {
|
|
7067
|
+
const shared = [];
|
|
7068
|
+
let inside = false;
|
|
7069
|
+
let textDepth = 0;
|
|
7070
|
+
let phoneticDepth = 0;
|
|
7071
|
+
let text = "";
|
|
7072
|
+
let parseError;
|
|
7073
|
+
const parser = newParser((error) => {
|
|
7074
|
+
parseError = error;
|
|
7075
|
+
});
|
|
7076
|
+
parser.on("opentag", (tag) => {
|
|
7077
|
+
const name = localName(tag.name);
|
|
7078
|
+
if (name === "si") {
|
|
7079
|
+
inside = true;
|
|
7080
|
+
text = "";
|
|
7081
|
+
} else if (inside && name === "rPh") phoneticDepth += 1;
|
|
7082
|
+
else if (inside && name === "t" && phoneticDepth === 0) textDepth += 1;
|
|
7083
|
+
});
|
|
7084
|
+
parser.on("text", (value) => {
|
|
7085
|
+
if (inside && textDepth > 0 && phoneticDepth === 0) text += value;
|
|
7086
|
+
});
|
|
7087
|
+
parser.on("cdata", (value) => {
|
|
7088
|
+
if (inside && textDepth > 0 && phoneticDepth === 0) text += value;
|
|
7089
|
+
});
|
|
7090
|
+
parser.on("closetag", (nameValue) => {
|
|
7091
|
+
const name = localName(nameValue);
|
|
7092
|
+
if (name === "t" && textDepth > 0) textDepth -= 1;
|
|
7093
|
+
else if (name === "rPh" && phoneticDepth > 0) phoneticDepth -= 1;
|
|
7094
|
+
else if (name === "si" && inside) {
|
|
7095
|
+
shared.push(text);
|
|
7096
|
+
inside = false;
|
|
7097
|
+
text = "";
|
|
7098
|
+
}
|
|
7099
|
+
});
|
|
7100
|
+
const state = { found: false };
|
|
7101
|
+
const decoder = new TextDecoder();
|
|
7102
|
+
for await (const chunk of entryChunks(source, SHARED_STRINGS, state)) parser.write(decoder.decode(chunk, { stream: true }));
|
|
7103
|
+
if (!state.found) return [];
|
|
7104
|
+
parser.write(decoder.decode());
|
|
7105
|
+
parser.close();
|
|
7106
|
+
if (parseError !== void 0) fail(`The workbook shared strings could not be parsed as XML: ${parseError.message}`);
|
|
7107
|
+
return shared;
|
|
7108
|
+
}
|
|
7109
|
+
function scanWorksheet(source, path, shared, dateStyles, date1904) {
|
|
7110
|
+
return (async function* () {
|
|
7111
|
+
const queue = [];
|
|
7112
|
+
let previousRow = 0;
|
|
7113
|
+
let lastYielded = 0;
|
|
7114
|
+
let rowNumber = 0;
|
|
7115
|
+
let cells = [];
|
|
7116
|
+
let nextColumn = 0;
|
|
7117
|
+
let cell;
|
|
7118
|
+
let parseError;
|
|
7119
|
+
const parser = newParser((error) => {
|
|
7120
|
+
parseError = error;
|
|
7121
|
+
});
|
|
7122
|
+
const drain = async function* () {
|
|
7123
|
+
for (const entry of queue.splice(0)) {
|
|
7124
|
+
for (let gap = lastYielded + 1; gap < entry.row; gap += 1) yield {
|
|
7125
|
+
row: gap,
|
|
7126
|
+
cells: []
|
|
7127
|
+
};
|
|
7128
|
+
lastYielded = entry.row;
|
|
7129
|
+
yield entry;
|
|
7130
|
+
}
|
|
7131
|
+
};
|
|
7132
|
+
parser.on("opentag", (tag) => {
|
|
7133
|
+
const name = localName(tag.name);
|
|
7134
|
+
if (name === "row") {
|
|
7135
|
+
const declared = Number(attribute(tag, "r"));
|
|
7136
|
+
rowNumber = Number.isInteger(declared) && declared > 0 ? declared : previousRow + 1;
|
|
7137
|
+
previousRow = rowNumber;
|
|
7138
|
+
cells = [];
|
|
7139
|
+
nextColumn = 0;
|
|
7140
|
+
return;
|
|
7141
|
+
}
|
|
7142
|
+
if (name === "c") {
|
|
7143
|
+
const column = columnIndex(attribute(tag, "r")) ?? nextColumn;
|
|
7144
|
+
cell = {
|
|
7145
|
+
type: attribute(tag, "t"),
|
|
7146
|
+
style: Number(attribute(tag, "s") ?? "0"),
|
|
7147
|
+
column,
|
|
7148
|
+
raw: "",
|
|
7149
|
+
inline: "",
|
|
7150
|
+
valueDepth: 0,
|
|
7151
|
+
inlineDepth: 0,
|
|
7152
|
+
textDepth: 0,
|
|
7153
|
+
phoneticDepth: 0
|
|
7154
|
+
};
|
|
7155
|
+
nextColumn = column + 1;
|
|
7156
|
+
} else if (cell !== void 0 && name === "v") cell.valueDepth += 1;
|
|
7157
|
+
else if (cell !== void 0 && name === "is") cell.inlineDepth += 1;
|
|
7158
|
+
else if (cell !== void 0 && name === "rPh" && cell.inlineDepth > 0) cell.phoneticDepth += 1;
|
|
7159
|
+
else if (cell !== void 0 && name === "t" && cell.inlineDepth > 0 && cell.phoneticDepth === 0) cell.textDepth += 1;
|
|
7160
|
+
});
|
|
7161
|
+
parser.on("text", (value) => {
|
|
7162
|
+
if (cell === void 0) return;
|
|
7163
|
+
if (cell.valueDepth > 0) cell.raw += value;
|
|
7164
|
+
if (cell.textDepth > 0 && cell.phoneticDepth === 0) cell.inline += value;
|
|
7165
|
+
});
|
|
7166
|
+
parser.on("cdata", (value) => {
|
|
7167
|
+
if (cell === void 0) return;
|
|
7168
|
+
if (cell.valueDepth > 0) cell.raw += value;
|
|
7169
|
+
if (cell.textDepth > 0 && cell.phoneticDepth === 0) cell.inline += value;
|
|
7170
|
+
});
|
|
7171
|
+
parser.on("closetag", (nameValue) => {
|
|
7172
|
+
const name = localName(nameValue);
|
|
7173
|
+
if (cell !== void 0 && name === "t" && cell.textDepth > 0) cell.textDepth -= 1;
|
|
7174
|
+
else if (cell !== void 0 && name === "rPh" && cell.phoneticDepth > 0) cell.phoneticDepth -= 1;
|
|
7175
|
+
else if (cell !== void 0 && name === "is" && cell.inlineDepth > 0) cell.inlineDepth -= 1;
|
|
7176
|
+
else if (cell !== void 0 && name === "v" && cell.valueDepth > 0) cell.valueDepth -= 1;
|
|
7177
|
+
else if (name === "c" && cell !== void 0) {
|
|
7178
|
+
let text = cell.raw;
|
|
7179
|
+
if (cell.type === "inlineStr") text = cell.inline;
|
|
7180
|
+
else if (cell.type === "s") {
|
|
7181
|
+
const index = Number(cell.raw);
|
|
7182
|
+
text = Number.isInteger(index) ? shared[index] ?? "" : "";
|
|
7183
|
+
} else if (cell.type === "b") text = cell.raw === "1" ? "TRUE" : "FALSE";
|
|
7184
|
+
else if (cell.type !== "str" && cell.type !== "e" && cell.raw !== "") {
|
|
7185
|
+
const numeric = Number(cell.raw);
|
|
7186
|
+
if (Number.isFinite(numeric) && Number.isInteger(cell.style) && dateStyles[cell.style] === true) text = serialToIso(numeric, date1904);
|
|
7187
|
+
}
|
|
7188
|
+
for (let gap = cells.length; gap < cell.column; gap += 1) cells.push("");
|
|
7189
|
+
if (cells.length > cell.column) cells[cell.column] = text;
|
|
7190
|
+
else cells.push(text);
|
|
7191
|
+
cell = void 0;
|
|
7192
|
+
} else if (name === "row") {
|
|
7193
|
+
while (cells.length > 0 && cells[cells.length - 1] === "") cells.pop();
|
|
7194
|
+
if (cells.length > 0) queue.push({
|
|
7195
|
+
row: rowNumber,
|
|
7196
|
+
cells
|
|
7197
|
+
});
|
|
7198
|
+
cells = [];
|
|
7199
|
+
}
|
|
7200
|
+
});
|
|
7201
|
+
const state = { found: false };
|
|
7202
|
+
const decoder = new TextDecoder();
|
|
7203
|
+
for await (const chunk of entryChunks(source, path, state)) {
|
|
7204
|
+
parser.write(decoder.decode(chunk, { stream: true }));
|
|
7205
|
+
yield* drain();
|
|
7206
|
+
}
|
|
7207
|
+
if (!state.found) fail(`The worksheet entry "${path}" could not be located inside the workbook.`);
|
|
7208
|
+
parser.write(decoder.decode());
|
|
7209
|
+
parser.close();
|
|
7210
|
+
if (parseError !== void 0) fail(`The worksheet "${path}" could not be parsed as XML: ${parseError.message}`);
|
|
7211
|
+
yield* drain();
|
|
7212
|
+
})();
|
|
7213
|
+
}
|
|
7214
|
+
function blank(cells) {
|
|
7215
|
+
return cells.every((value) => value.trim() === "");
|
|
7216
|
+
}
|
|
7217
|
+
function wide(code) {
|
|
7218
|
+
return code >= 19968 && code <= 40959 || code >= 13312 && code <= 19903 || code >= 12288 && code <= 12543 || code >= 44032 && code <= 55215 || code >= 63744 && code <= 64255 || code >= 65280 && code <= 65519;
|
|
7219
|
+
}
|
|
7220
|
+
const MAX_CACHED_ROWS = 5e4;
|
|
7221
|
+
const MAX_CACHED_CELLS = 5e5;
|
|
7222
|
+
async function measure(sheet) {
|
|
7223
|
+
let rowCount = 0;
|
|
7224
|
+
let columnCount = 0;
|
|
7225
|
+
let firstNonEmptyRow = 0;
|
|
7226
|
+
let firstRow = [];
|
|
7227
|
+
let dataRows = 0;
|
|
7228
|
+
let wideChars = 0;
|
|
7229
|
+
let otherChars = sheet.name.length + 8;
|
|
7230
|
+
let cellCount = 0;
|
|
7231
|
+
const rows = [];
|
|
7232
|
+
for await (const entry of sheet.scan()) {
|
|
7233
|
+
rowCount += 1;
|
|
7234
|
+
cellCount += entry.cells.length;
|
|
7235
|
+
if (rowCount <= MAX_CACHED_ROWS && cellCount <= MAX_CACHED_CELLS) rows.push(entry);
|
|
7236
|
+
columnCount = Math.max(columnCount, entry.cells.length);
|
|
7237
|
+
otherChars += Math.max(entry.cells.length - 1, 0) + 1;
|
|
7238
|
+
for (const value of entry.cells) for (let index = 0; index < value.length; index += 1) if (wide(value.charCodeAt(index))) wideChars += 1;
|
|
7239
|
+
else otherChars += 1;
|
|
7240
|
+
if (blank(entry.cells)) continue;
|
|
7241
|
+
if (firstNonEmptyRow === 0) {
|
|
7242
|
+
firstNonEmptyRow = entry.row;
|
|
7243
|
+
firstRow = entry.cells;
|
|
7244
|
+
} else dataRows += 1;
|
|
7245
|
+
}
|
|
7246
|
+
return {
|
|
7247
|
+
meta: {
|
|
7248
|
+
rowCount,
|
|
7249
|
+
columnCount,
|
|
7250
|
+
firstNonEmptyRow,
|
|
7251
|
+
firstRow,
|
|
7252
|
+
dataRows,
|
|
7253
|
+
estimatedTokens: wideChars + Math.ceil(otherChars / 4),
|
|
7254
|
+
textChars: wideChars + otherChars
|
|
7255
|
+
},
|
|
7256
|
+
...rowCount <= MAX_CACHED_ROWS && cellCount <= MAX_CACHED_CELLS ? { rows } : {}
|
|
7257
|
+
};
|
|
7258
|
+
}
|
|
7259
|
+
function resolveSheetPath(target) {
|
|
7260
|
+
const clean = target.replace(/^\.\//, "");
|
|
7261
|
+
return clean.startsWith("/") ? clean.slice(1) : `xl/${clean}`;
|
|
7262
|
+
}
|
|
7263
|
+
async function readStreamingXlsxWorkbook(source) {
|
|
7264
|
+
if (typeof source !== "function" && OLE2_SIGNATURE.every((byte, index) => source[index] === byte)) fail("This is a legacy .xls workbook, which is not supported. Save it as .xlsx and try again.");
|
|
7265
|
+
const workbookBytes = await entryBytes(source, WORKBOOK);
|
|
7266
|
+
if (workbookBytes === void 0) fail(`This file is not an Excel workbook: it has no ${WORKBOOK} entry.`);
|
|
7267
|
+
const workbook = parseXml$1(workbookBytes, "index");
|
|
7268
|
+
const workbookPr = byTag$2(workbook, "workbookPr")[0];
|
|
7269
|
+
const date1904 = workbookPr?.getAttribute("date1904") === "1" || workbookPr?.getAttribute("date1904") === "true";
|
|
7270
|
+
const relsBytes = await entryBytes(source, WORKBOOK_RELS);
|
|
7271
|
+
const targets = /* @__PURE__ */ new Map();
|
|
7272
|
+
if (relsBytes !== void 0) for (const rel of byTag$2(parseXml$1(relsBytes, "relationships"), "Relationship")) {
|
|
7273
|
+
const id = rel.getAttribute("Id");
|
|
7274
|
+
const target = rel.getAttribute("Target");
|
|
7275
|
+
if (id !== null && target !== null) targets.set(id, resolveSheetPath(target));
|
|
7276
|
+
}
|
|
7277
|
+
const [shared, dateStyles] = await Promise.all([readSharedStrings(source), entryBytes(source, STYLES).then((bytes) => readDateStyles(bytes))]);
|
|
7278
|
+
const sheets = [];
|
|
7279
|
+
for (const [ordinal, sheet] of byTag$2(workbook, "sheet").entries()) {
|
|
7280
|
+
const name = sheet.getAttribute("name") ?? `Sheet${ordinal + 1}`;
|
|
7281
|
+
const relId = sheet.getAttributeNS("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id") ?? sheet.getAttribute("r:id");
|
|
7282
|
+
const path = relId !== null ? targets.get(relId) : void 0;
|
|
7283
|
+
if (path === void 0) fail(`The worksheet "${name}" could not be located inside the workbook.`);
|
|
7284
|
+
let metadata;
|
|
7285
|
+
let cachedRows;
|
|
7286
|
+
const scan = () => {
|
|
7287
|
+
const rows = cachedRows;
|
|
7288
|
+
if (rows !== void 0) return (async function* () {
|
|
7289
|
+
yield* rows;
|
|
7290
|
+
})();
|
|
7291
|
+
return scanWorksheet(source, path, shared, dateStyles, date1904);
|
|
7292
|
+
};
|
|
7293
|
+
const entry = {
|
|
7294
|
+
name,
|
|
7295
|
+
scan,
|
|
7296
|
+
meta: () => {
|
|
7297
|
+
metadata ??= measure({
|
|
7298
|
+
name,
|
|
7299
|
+
scan
|
|
7300
|
+
}).then((result) => {
|
|
7301
|
+
cachedRows = result.rows;
|
|
7302
|
+
return result.meta;
|
|
7303
|
+
}).catch((error) => {
|
|
7304
|
+
metadata = void 0;
|
|
7305
|
+
throw error;
|
|
7306
|
+
});
|
|
7307
|
+
return metadata;
|
|
7308
|
+
}
|
|
7309
|
+
};
|
|
7310
|
+
sheets.push(entry);
|
|
7311
|
+
}
|
|
7312
|
+
return {
|
|
7313
|
+
kind: "streaming",
|
|
7314
|
+
sheets
|
|
7315
|
+
};
|
|
7316
|
+
}
|
|
7317
|
+
|
|
6954
7318
|
//#endregion
|
|
6955
7319
|
//#region ../browser/src/document/xlsxTable.ts
|
|
6956
7320
|
/**
|
|
6957
|
-
* xlsx →
|
|
7321
|
+
* xlsx → 单元格网格或可重复扫描的行流。
|
|
6958
7322
|
*
|
|
6959
|
-
*
|
|
6960
|
-
*
|
|
6961
|
-
* 错误语义同 `extractXlsxText`:旧版 `.xls`、归档损坏、缺 `xl/workbook.xml` 都抛 `WebSkillError`。
|
|
7323
|
+
* `read` 保留既有网格契约;`readStreaming` 用 SAX 逐行解析工作表,不受整包解压的 64 MiB 条目上限约束。
|
|
7324
|
+
* 两条路径使用同一套单元格取值、日期换算与空格补位规则,错误均带 `WebSkillError`。
|
|
6962
7325
|
* @experimental
|
|
6963
7326
|
*/
|
|
6964
7327
|
function createXlsxTableReader() {
|
|
6965
|
-
return {
|
|
7328
|
+
return {
|
|
7329
|
+
read: readXlsxTable,
|
|
7330
|
+
readStreaming: readStreamingXlsxWorkbook
|
|
7331
|
+
};
|
|
6966
7332
|
}
|
|
6967
7333
|
async function readXlsxTable(bytes) {
|
|
6968
7334
|
const { sheets } = await readXlsxWorkbook(bytes);
|