documonster 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README_zh.md +1 -1
- package/dist/esm/modules/archive/compression/compress.base.js +20 -6
- package/dist/esm/modules/archive/compression/compress.browser.js +45 -32
- package/dist/esm/modules/archive/compression/compress.js +74 -18
- package/dist/esm/modules/archive/compression/deflate-fallback.js +14 -3
- package/dist/esm/modules/archive/compression/worker-pool/pool.browser.js +9 -3
- package/dist/esm/modules/archive/compression/worker-pool/worker-script.js +35 -7
- package/dist/esm/modules/archive/core/errors.js +26 -4
- package/dist/esm/modules/archive/index.base.js +1 -1
- package/dist/esm/modules/archive/unzip/zip-extract-core.js +74 -34
- package/dist/esm/modules/archive/unzip/zip-parser.js +55 -9
- package/dist/esm/modules/archive/zip-spec/zip-parser-core.js +14 -2
- package/dist/esm/modules/csv/parse/scanner/scanner.js +3 -0
- package/dist/esm/modules/csv/parse/sync.js +3 -2
- package/dist/esm/modules/csv/stream/parser.js +40 -4
- package/dist/esm/modules/csv/worker/worker-script.generated.js +1 -1
- package/dist/esm/modules/excel/core/cell.js +22 -2
- package/dist/esm/modules/excel/core/table.js +39 -2
- package/dist/esm/modules/excel/core/worksheet-core.js +39 -0
- package/dist/esm/modules/excel/core/worksheet-load.js +3 -1
- package/dist/esm/modules/excel/stream/workbook-reader.browser.js +34 -11
- package/dist/esm/modules/excel/surface/cell.js +64 -23
- package/dist/esm/modules/excel/utils/cell-format.js +3 -2
- package/dist/esm/modules/excel/xlsb/read/package.js +3 -1
- package/dist/esm/modules/excel/xlsx/read/package.js +17 -1
- package/dist/esm/modules/pdf/builder/document-builder.js +3 -1
- package/dist/esm/modules/pdf/builder/pdf-editor.js +218 -58
- package/dist/esm/modules/pdf/core/pdf-kdf.browser.js +9 -1
- package/dist/esm/modules/pdf/core/pdf-kdf.js +8 -0
- package/dist/esm/modules/pdf/core/pdf-writer.js +159 -149
- package/dist/esm/modules/pdf/core/pdfa.js +7 -3
- package/dist/esm/modules/pdf/errors.js +25 -0
- package/dist/esm/modules/pdf/index.js +1 -1
- package/dist/esm/modules/pdf/reader/pdf-decrypt.js +136 -74
- package/dist/esm/modules/pdf/reader/pdf-document.js +314 -105
- package/dist/esm/modules/pdf/reader/pdf-parser.js +29 -11
- package/dist/esm/modules/pdf/reader/pdf-reader.js +8 -1
- package/dist/esm/modules/pdf/reader/stream-filters.js +139 -77
- package/dist/esm/modules/pdf/render/pdf-exporter.js +3 -1
- package/dist/esm/modules/pdf/word-bridge.js +22 -48
- package/dist/esm/modules/word/advanced/field-engine.js +75 -56
- package/dist/esm/modules/word/builder/document-handle.js +15 -1
- package/dist/esm/modules/word/convert/docx-to-semantic.js +84 -83
- package/dist/esm/modules/word/convert/html/html-renderer.js +107 -78
- package/dist/esm/modules/word/convert/markdown/markdown-import.js +43 -10
- package/dist/esm/modules/word/convert/markdown/markdown-renderer.js +98 -130
- package/dist/esm/modules/word/convert/odt/odt.js +149 -55
- package/dist/esm/modules/word/core/text-utils.js +9 -0
- package/dist/esm/modules/word/errors.js +1 -1
- package/dist/esm/modules/word/layout/layout-constants.js +20 -23
- package/dist/esm/modules/word/layout/layout-full.js +259 -280
- package/dist/esm/modules/word/layout/layout.js +140 -197
- package/dist/esm/modules/word/query/final-view.js +49 -0
- package/dist/esm/modules/word/query/heading.js +81 -0
- package/dist/esm/modules/word/query/merge.js +39 -22
- package/dist/esm/modules/word/query/numbering-counter.js +108 -0
- package/dist/esm/modules/word/query/page-field.js +212 -0
- package/dist/esm/modules/word/query/search.js +15 -14
- package/dist/esm/modules/word/query/split.js +15 -25
- package/dist/esm/modules/word/query/style-resolve.js +196 -53
- package/dist/esm/modules/word/query/style-resolver.js +24 -0
- package/dist/esm/modules/word/reader/chart-parser.js +17 -7
- package/dist/esm/modules/word/reader/comments-parser.js +4 -4
- package/dist/esm/modules/word/reader/doc-props-parsers.js +10 -9
- package/dist/esm/modules/word/reader/docx-reader.js +46 -32
- package/dist/esm/modules/word/reader/metadata-parsers.js +5 -5
- package/dist/esm/modules/word/reader/numbering-parser.js +4 -3
- package/dist/esm/modules/word/reader/part-xml.js +26 -0
- package/dist/esm/modules/word/reader/reader-context.js +3 -3
- package/dist/esm/modules/word/reader/settings-parser.js +3 -3
- package/dist/esm/modules/word/reader/styles-parser.js +3 -3
- package/dist/esm/modules/word/reader/theme-parser.js +4 -3
- package/dist/esm/modules/word/surface/query.js +1 -1
- package/dist/esm/modules/word/writer/docx-packager.js +4 -1
- package/dist/esm/modules/word/writer/streaming-writer.js +11 -2
- package/dist/esm/modules/xml/dom.js +4 -8
- package/dist/esm/modules/xml/errors.js +1 -3
- package/dist/esm/modules/xml/sax.js +8 -7
- package/dist/esm/modules/xml/to-object.js +4 -8
- package/dist/esm/utils/crypto.browser.js +147 -0
- package/dist/esm/utils/crypto.js +14 -0
- package/dist/esm/utils/limits.js +19 -0
- package/dist/iife/documonster.archive.iife.min.js +39 -11
- package/dist/iife/documonster.csv.iife.min.js +17 -17
- package/dist/iife/documonster.draw.iife.min.js +1 -1
- package/dist/iife/documonster.excel.iife.min.js +88 -60
- package/dist/iife/documonster.formula.iife.min.js +1 -1
- package/dist/iife/documonster.markdown.iife.min.js +1 -1
- package/dist/iife/documonster.mermaid.iife.min.js +1 -1
- package/dist/iife/documonster.pdf.iife.min.js +44 -42
- package/dist/iife/documonster.stream.iife.min.js +1 -1
- package/dist/iife/documonster.word.iife.min.js +95 -67
- package/dist/iife/documonster.xml.iife.min.js +6 -6
- package/dist/types/modules/archive/compression/compress.base.d.ts +12 -3
- package/dist/types/modules/archive/compression/compress.browser.d.ts +7 -4
- package/dist/types/modules/archive/compression/compress.d.ts +9 -4
- package/dist/types/modules/archive/compression/deflate-fallback.d.ts +3 -1
- package/dist/types/modules/archive/compression/worker-pool/pool.browser.d.ts +4 -1
- package/dist/types/modules/archive/compression/worker-pool/types.d.ts +4 -0
- package/dist/types/modules/archive/core/errors.d.ts +31 -2
- package/dist/types/modules/archive/index.base.d.ts +1 -1
- package/dist/types/modules/archive/unzip/zip-extract-core.d.ts +9 -2
- package/dist/types/modules/archive/unzip/zip-parser.d.ts +33 -0
- package/dist/types/modules/archive/zip-spec/zip-parser-core.d.ts +6 -0
- package/dist/types/modules/csv/parse/scanner/types.d.ts +5 -0
- package/dist/types/modules/csv/stream/parser.d.ts +16 -0
- package/dist/types/modules/csv/worker/worker-script.generated.d.ts +1 -1
- package/dist/types/modules/excel/core/table.d.ts +15 -0
- package/dist/types/modules/excel/core/worksheet-core.d.ts +26 -0
- package/dist/types/modules/excel/stream/workbook-reader.browser.d.ts +11 -0
- package/dist/types/modules/excel/surface/cell.d.ts +8 -8
- package/dist/types/modules/excel/xlsx/types.d.ts +16 -0
- package/dist/types/modules/pdf/builder/document-builder.d.ts +7 -0
- package/dist/types/modules/pdf/builder/pdf-editor.d.ts +49 -5
- package/dist/types/modules/pdf/core/pdf-kdf.browser.d.ts +4 -0
- package/dist/types/modules/pdf/core/pdf-kdf.d.ts +4 -0
- package/dist/types/modules/pdf/core/pdf-writer.d.ts +49 -10
- package/dist/types/modules/pdf/core/pdfa.d.ts +2 -0
- package/dist/types/modules/pdf/errors.d.ts +19 -0
- package/dist/types/modules/pdf/index.d.ts +2 -2
- package/dist/types/modules/pdf/reader/pdf-document.d.ts +83 -5
- package/dist/types/modules/pdf/reader/pdf-parser.d.ts +2 -2
- package/dist/types/modules/pdf/reader/pdf-reader.d.ts +7 -0
- package/dist/types/modules/pdf/reader/stream-filters.d.ts +5 -1
- package/dist/types/modules/pdf/types.d.ts +7 -0
- package/dist/types/modules/word/convert/conversion-ir.d.ts +2 -0
- package/dist/types/modules/word/core/text-utils.d.ts +7 -1
- package/dist/types/modules/word/errors.d.ts +3 -3
- package/dist/types/modules/word/index.base.d.ts +1 -1
- package/dist/types/modules/word/layout/layout-constants.d.ts +13 -9
- package/dist/types/modules/word/query/final-view.d.ts +26 -0
- package/dist/types/modules/word/query/heading.d.ts +30 -0
- package/dist/types/modules/word/query/numbering-counter.d.ts +47 -0
- package/dist/types/modules/word/query/page-field.d.ts +79 -0
- package/dist/types/modules/word/query/search.d.ts +8 -2
- package/dist/types/modules/word/query/split.d.ts +4 -1
- package/dist/types/modules/word/query/style-resolve.d.ts +58 -11
- package/dist/types/modules/word/query/style-resolver.d.ts +29 -0
- package/dist/types/modules/word/reader/chart-parser.d.ts +2 -2
- package/dist/types/modules/word/reader/comments-parser.d.ts +1 -1
- package/dist/types/modules/word/reader/doc-props-parsers.d.ts +4 -4
- package/dist/types/modules/word/reader/metadata-parsers.d.ts +2 -2
- package/dist/types/modules/word/reader/numbering-parser.d.ts +1 -1
- package/dist/types/modules/word/reader/part-xml.d.ts +14 -0
- package/dist/types/modules/word/reader/reader-context.d.ts +1 -1
- package/dist/types/modules/word/reader/settings-parser.d.ts +1 -1
- package/dist/types/modules/word/reader/styles-parser.d.ts +1 -1
- package/dist/types/modules/word/reader/theme-parser.d.ts +1 -1
- package/dist/types/modules/word/surface/query.d.ts +2 -1
- package/dist/types/modules/word/types.d.ts +5 -1
- package/dist/types/modules/word/writer/docx-packager.d.ts +7 -0
- package/dist/types/modules/word/writer/streaming-writer.d.ts +7 -0
- package/dist/types/modules/xml/errors.d.ts +9 -0
- package/dist/types/modules/xml/index.d.ts +1 -0
- package/dist/types/modules/xml/sax.d.ts +2 -1
- package/dist/types/utils/crypto.browser.d.ts +10 -0
- package/dist/types/utils/crypto.d.ts +10 -0
- package/dist/types/utils/limits.d.ts +12 -0
- package/package.json +1 -1
|
@@ -1280,13 +1280,33 @@ class FormulaValue {
|
|
|
1280
1280
|
return this._translatedFormula;
|
|
1281
1281
|
}
|
|
1282
1282
|
toCsvString() {
|
|
1283
|
-
return
|
|
1283
|
+
return formulaResultText(this.model.result, true);
|
|
1284
1284
|
}
|
|
1285
1285
|
release() { }
|
|
1286
1286
|
toString() {
|
|
1287
|
-
return this.model.result
|
|
1287
|
+
return formulaResultText(this.model.result, false);
|
|
1288
1288
|
}
|
|
1289
1289
|
}
|
|
1290
|
+
/**
|
|
1291
|
+
* A formula's cached result as text — the same text the result would have as a plain cell value.
|
|
1292
|
+
*
|
|
1293
|
+
* Written out rather than `result ? result.toString() : ""`, which had two bugs: a falsy result (`0`,
|
|
1294
|
+
* `false`) read as no result at all, and an error result is an object, so it read `"[object Object]"`
|
|
1295
|
+
* where a stored error reads its code. A `Date` renders as {@link DateValue} renders one: ISO for CSV,
|
|
1296
|
+
* `Date#toString` otherwise.
|
|
1297
|
+
*/
|
|
1298
|
+
function formulaResultText(result, csv) {
|
|
1299
|
+
if (result === undefined || result === null) {
|
|
1300
|
+
return "";
|
|
1301
|
+
}
|
|
1302
|
+
if (result instanceof Date) {
|
|
1303
|
+
return csv ? result.toISOString() : result.toString();
|
|
1304
|
+
}
|
|
1305
|
+
if (typeof result === "object") {
|
|
1306
|
+
return result.error;
|
|
1307
|
+
}
|
|
1308
|
+
return String(result);
|
|
1309
|
+
}
|
|
1290
1310
|
class SharedStringValue {
|
|
1291
1311
|
constructor(cell, value) {
|
|
1292
1312
|
this.model = { address: cell.address, type: Types.SharedString, value };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { cellGetValue, cellSetValue, setFacetShared } from "./cell.js";
|
|
1
|
+
import { cellFormula, cellGetValue, cellResult, cellSetValue, setFacetShared } from "./cell.js";
|
|
2
2
|
import { sharedCellFacet } from "./style-sharing.js";
|
|
3
|
-
import { getRow, getSheetWorkbook, rowGetCell } from "./worksheet-core.js";
|
|
3
|
+
import { findCell, getRow, getSheetWorkbook, rowGetCell } from "./worksheet-core.js";
|
|
4
4
|
import { TableError } from "../errors.js";
|
|
5
5
|
import { colCache } from "../utils/col-cache.js";
|
|
6
6
|
function clearStaleSortState(t) {
|
|
@@ -107,6 +107,43 @@ const SUBTOTAL_FUNCTIONS = {
|
|
|
107
107
|
var: 110,
|
|
108
108
|
sum: 109
|
|
109
109
|
};
|
|
110
|
+
/**
|
|
111
|
+
* Carry the totals row's cached results from the loaded sheet into a table model — **for a reader only**.
|
|
112
|
+
*
|
|
113
|
+
* The results are `<v>` values in the sheet's cells; the table part has nowhere to keep them, and
|
|
114
|
+
* {@link createTable} rewrites the totals cells from the model. A reader that does not call this loses
|
|
115
|
+
* every cached total on load.
|
|
116
|
+
*
|
|
117
|
+
* It belongs to the load path and nowhere else. A cached value is evidence about the data the *file*
|
|
118
|
+
* held; a table a caller builds with `Table.add` brings its own rows, and an old result sitting in the
|
|
119
|
+
* same cell — even under an identical formula — says nothing about them.
|
|
120
|
+
*
|
|
121
|
+
* `range` is the table's full extent (header and totals included). Only a result cached under the exact
|
|
122
|
+
* formula this table writes is taken, and a result the model already carries wins.
|
|
123
|
+
*/
|
|
124
|
+
export function adoptLoadedTotals(worksheet, table, range) {
|
|
125
|
+
if (table.totalsRow !== true) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const decoded = colCache.decode(range);
|
|
129
|
+
if (!("dimensions" in decoded)) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const t = { worksheet, table };
|
|
133
|
+
table.columns.forEach((column, j) => {
|
|
134
|
+
if (j === 0 || column.totalsRowResult !== undefined) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const cell = findCell(worksheet, decoded.bottom, decoded.left + j);
|
|
138
|
+
if (!cell) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const result = cellResult(cell);
|
|
142
|
+
if (result !== undefined && cellFormula(cell) === tableGetFormula(t, column)) {
|
|
143
|
+
column.totalsRowResult = result;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
110
147
|
/** Create a table bound to a worksheet, validating + storing on-sheet if a model is given. */
|
|
111
148
|
export function createTable(worksheet, table) {
|
|
112
149
|
const t = { worksheet, table: table };
|
|
@@ -173,6 +173,45 @@ export function findCell(ws, r, c) {
|
|
|
173
173
|
const row = ws._rows[address.row - 1];
|
|
174
174
|
return row ? rowFindCell(row, address.col) : undefined;
|
|
175
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* The existing cell at a reference, or `undefined` — resolved the way {@link getCell} resolves it, with
|
|
178
|
+
* the same errors for a malformed reference, but **without creating** anything.
|
|
179
|
+
*
|
|
180
|
+
* This is what a public reader resolves through. `getCell` materialises the row and the cell, so a read
|
|
181
|
+
* through it widened `rowCount`, `<dimension>` and, in a styled row or column, wrote a styled empty cell
|
|
182
|
+
* into the saved file (see `core/__tests__/read-side-effects.test.ts`).
|
|
183
|
+
*
|
|
184
|
+
* Validation matches `getCell` exactly, including its leniency: both decode the reference with
|
|
185
|
+
* `colCache.getAddress`, and `getCell` validates the *decoded* address only when it has to create a cell
|
|
186
|
+
* (in `cellCreate`). So this validates only on a miss, and a reference that decodes to an existing cell
|
|
187
|
+
* is accepted by both — strict validation of the raw string would be a separate, wider change. The hit
|
|
188
|
+
* path therefore allocates nothing and checks nothing beyond the decode.
|
|
189
|
+
*/
|
|
190
|
+
export function locateCell(ws, r, c) {
|
|
191
|
+
const decoded = colCache.getAddress(r, c);
|
|
192
|
+
const cell = ws._rows[decoded.row - 1]?.cells[decoded.col - 1];
|
|
193
|
+
if (cell === undefined) {
|
|
194
|
+
colCache.validateAddress(decoded.address);
|
|
195
|
+
}
|
|
196
|
+
return cell;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* The fully-qualified address of a reference, validated like {@link getCell} — for a reader that answers
|
|
200
|
+
* from the address alone (defined names, validation rules, an absent cell's inherited format).
|
|
201
|
+
*/
|
|
202
|
+
export function resolveAddress(ws, r, c) {
|
|
203
|
+
const decoded = colCache.getAddress(r, c);
|
|
204
|
+
colCache.validateAddress(decoded.address);
|
|
205
|
+
return { sheetName: ws._name, address: decoded.address, row: decoded.row, col: decoded.col };
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* The number format an empty cell at `(row, col)` would inherit if it were
|
|
209
|
+
* created — the row's, else the column's — read without creating the row, the
|
|
210
|
+
* column record or the cell. Mirrors the `numFmt` precedence in `mergeCellStyle`.
|
|
211
|
+
*/
|
|
212
|
+
export function inheritedNumFmt(ws, row, col) {
|
|
213
|
+
return ws._rows[row - 1]?.style.numFmt || ws._columns[col - 1]?.style.numFmt || undefined;
|
|
214
|
+
}
|
|
176
215
|
export function getCell(ws, r, c) {
|
|
177
216
|
const address = colCache.getAddress(r, c);
|
|
178
217
|
const row = getRow(ws, address.row);
|
|
@@ -3,7 +3,7 @@ import { createDataValidations } from "./data-validations.js";
|
|
|
3
3
|
import { formCheckboxFromModel } from "./form-control.js";
|
|
4
4
|
import { imageCreate } from "./image.js";
|
|
5
5
|
import { rowCreate } from "./row.js";
|
|
6
|
-
import { createTable, tableSetModel } from "./table.js";
|
|
6
|
+
import { adoptLoadedTotals, createTable, tableSetModel } from "./table.js";
|
|
7
7
|
import { mergeCellsWithoutStyle, setSheetName } from "./worksheet.js";
|
|
8
8
|
import { columnFromModel, getSheetName, getSheetWorkbook, rowSetModel } from "./worksheet-core.js";
|
|
9
9
|
// Type for data validation model - maps address to validation
|
|
@@ -69,6 +69,8 @@ export function setSheetModel(ws, value) {
|
|
|
69
69
|
}
|
|
70
70
|
ws.sheetProtection = value.sheetProtection;
|
|
71
71
|
ws.tables = value.tables.reduce((tables, table) => {
|
|
72
|
+
// The cells were applied above, so the totals row's cached results are there to carry over.
|
|
73
|
+
adoptLoadedTotals(ws, table, table.tableRef ?? table.ref);
|
|
72
74
|
const t = createTable(ws, table);
|
|
73
75
|
tableSetModel(t, table);
|
|
74
76
|
tables[table.name] = t;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* Node.js uses `workbook-reader.ts`, which extends the same base implementation
|
|
9
9
|
* with filesystem-specific features (filename input + temp-file buffering).
|
|
10
10
|
*/
|
|
11
|
+
import { FileTooLargeError } from "../../archive/core/errors.js";
|
|
11
12
|
import { createParse } from "#platform/modules/archive/unzip/stream";
|
|
12
13
|
import { ExcelFileError } from "../errors.js";
|
|
13
14
|
import { HyperlinkReader } from "./hyperlink-reader.js";
|
|
@@ -72,10 +73,30 @@ import { MetadataXform } from "../xlsx/xform/core/metadata-xform.js";
|
|
|
72
73
|
import { RelationshipsXform } from "../xlsx/xform/core/relationships-xform.js";
|
|
73
74
|
import { parseXformStream } from "../xlsx/xform/parse-xform.js";
|
|
74
75
|
import { StylesXform } from "../xlsx/xform/style/styles-xform.js";
|
|
75
|
-
import { Readable } from "#platform/modules/stream/index";
|
|
76
|
+
import { Readable, Transform } from "#platform/modules/stream/index";
|
|
76
77
|
import { EventEmitter } from "../../../utils/event-emitter.js";
|
|
78
|
+
import { assertLimitOption } from "../../../utils/limits.js";
|
|
77
79
|
import { decodeOoxmlEscape } from "#platform/utils/utils";
|
|
78
80
|
import { SaxParser, saxStream } from "../../xml/sax.js";
|
|
81
|
+
/**
|
|
82
|
+
* `entry`'s bytes, failing with `FileTooLargeError` as soon as more than
|
|
83
|
+
* `limit` arrive — before a hostile part can be held in memory.
|
|
84
|
+
*/
|
|
85
|
+
function boundedPart(entry, limit) {
|
|
86
|
+
let seen = 0;
|
|
87
|
+
const bounded = new Transform({
|
|
88
|
+
transform(chunk, _encoding, callback) {
|
|
89
|
+
seen += chunk.length;
|
|
90
|
+
if (seen > limit) {
|
|
91
|
+
callback(new FileTooLargeError(entry.path, `holds more than ${limit} bytes (maxEntrySize)`));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
callback(null, chunk);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
entry.on("error", (err) => bounded.destroy(err));
|
|
98
|
+
return entry.pipe(bounded);
|
|
99
|
+
}
|
|
79
100
|
// ============================================================================
|
|
80
101
|
// Base Class
|
|
81
102
|
// ============================================================================
|
|
@@ -99,6 +120,8 @@ export class WorkbookReaderBase extends EventEmitter {
|
|
|
99
120
|
this.WorksheetReaderClass = WorksheetReaderClass;
|
|
100
121
|
this.HyperlinkReaderClass = HyperlinkReaderClass;
|
|
101
122
|
this._maxBufferedBytes = options.maxBufferedWorksheetBytes ?? 256 * 1024 * 1024;
|
|
123
|
+
assertLimitOption("maxEntrySize", options.maxEntrySize);
|
|
124
|
+
this._maxEntrySize = options.maxEntrySize ?? 512 * 1024 * 1024;
|
|
102
125
|
this.options = {
|
|
103
126
|
worksheets: "emit",
|
|
104
127
|
sharedStrings: "cache",
|
|
@@ -664,21 +687,21 @@ export class WorkbookReaderBase extends EventEmitter {
|
|
|
664
687
|
case OOXML_PATHS.rootRels:
|
|
665
688
|
break;
|
|
666
689
|
case OOXML_PATHS.xlWorkbookRels:
|
|
667
|
-
await this._parseRels(entry);
|
|
690
|
+
await this._parseRels(boundedPart(entry, this._maxEntrySize));
|
|
668
691
|
break;
|
|
669
692
|
case OOXML_PATHS.xlWorkbook:
|
|
670
|
-
await this._parseWorkbook(entry);
|
|
693
|
+
await this._parseWorkbook(boundedPart(entry, this._maxEntrySize));
|
|
671
694
|
break;
|
|
672
695
|
case OOXML_PATHS.xlSharedStrings:
|
|
673
|
-
for await (const item of this._parseSharedStrings(entry)) {
|
|
696
|
+
for await (const item of this._parseSharedStrings(boundedPart(entry, this._maxEntrySize))) {
|
|
674
697
|
yield { eventType: "shared-strings", value: item };
|
|
675
698
|
}
|
|
676
699
|
break;
|
|
677
700
|
case OOXML_PATHS.xlStyles:
|
|
678
|
-
await this._parseStyles(entry);
|
|
701
|
+
await this._parseStyles(boundedPart(entry, this._maxEntrySize));
|
|
679
702
|
break;
|
|
680
703
|
case OOXML_PATHS.xlMetadata:
|
|
681
|
-
await this._parseMetadata(entry);
|
|
704
|
+
await this._parseMetadata(boundedPart(entry, this._maxEntrySize));
|
|
682
705
|
break;
|
|
683
706
|
// **The binary package's three prerequisite parts.**
|
|
684
707
|
//
|
|
@@ -688,18 +711,18 @@ export class WorkbookReaderBase extends EventEmitter {
|
|
|
688
711
|
// problem in both containers, and were already solved here for one of them.
|
|
689
712
|
default:
|
|
690
713
|
if (normalizedPath.toLowerCase() === "xl/_rels/workbook.bin.rels") {
|
|
691
|
-
await this._parseRels(entry);
|
|
714
|
+
await this._parseRels(boundedPart(entry, this._maxEntrySize));
|
|
692
715
|
continue;
|
|
693
716
|
}
|
|
694
717
|
switch (xlsbPartKind(normalizedPath)) {
|
|
695
718
|
case "workbook":
|
|
696
|
-
await this._parseXlsbWorkbook(entry);
|
|
719
|
+
await this._parseXlsbWorkbook(boundedPart(entry, this._maxEntrySize));
|
|
697
720
|
continue;
|
|
698
721
|
case "sharedStrings":
|
|
699
|
-
await this._parseXlsbSharedStrings(entry);
|
|
722
|
+
await this._parseXlsbSharedStrings(boundedPart(entry, this._maxEntrySize));
|
|
700
723
|
continue;
|
|
701
724
|
case "styles":
|
|
702
|
-
await this._parseXlsbStyles(entry);
|
|
725
|
+
await this._parseXlsbStyles(boundedPart(entry, this._maxEntrySize));
|
|
703
726
|
continue;
|
|
704
727
|
default:
|
|
705
728
|
break;
|
|
@@ -735,7 +758,7 @@ export class WorkbookReaderBase extends EventEmitter {
|
|
|
735
758
|
}
|
|
736
759
|
sheetNo = getWorksheetNoFromWorksheetRelsPath(normalizedPath)?.toString();
|
|
737
760
|
if (sheetNo) {
|
|
738
|
-
yield* this._parseHyperlinks(iterateStream(entry), sheetNo);
|
|
761
|
+
yield* this._parseHyperlinks(iterateStream(boundedPart(entry, this._maxEntrySize)), sheetNo);
|
|
739
762
|
continue;
|
|
740
763
|
}
|
|
741
764
|
break;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { cellAddName, cellAlignment, cellDateKind, cellGetDateParts, cellGetTemporal, cellSetDateParts, cellBorder, cellComment,
|
|
1
|
+
import { cellAddName, cellAlignment, cellDateKind, cellGetDateParts, cellGetTemporal, cellSetDateParts, cellBorder, cellComment, cellDisplayText, cellEffectiveType, cellFill, cellFont, cellFormula, cellGetModel, cellOwnStyle, cellGetValue, cellHyperlink, cellIsMerged, cellMaster, cellNote, cellNumFmt, cellProtection, cellRemoveAllNames, cellRemoveName, cellResult, cellSetAlignment, cellSetBorder, cellSetComment, cellSetDataValidation, cellSetFill, cellSetFont, cellSetModel, cellSetName, cellSetNames, cellSetNote, cellSetNumFmt, cellSetProtection, cellSetResult, cellSetStyle, cellSetValue, cellText, cellType, cellView } from "../core/cell.js";
|
|
2
|
+
import { dataValidationFind } from "../core/data-validations.js";
|
|
3
|
+
import { definedNamesGetNamesEx } from "../core/defined-names.js";
|
|
4
|
+
import { ValueType } from "../core/enums.js";
|
|
2
5
|
import { getCellStyle } from "../core/workbook-core.js";
|
|
3
|
-
import {
|
|
6
|
+
import { getCell, getSheetWorkbook, inheritedNumFmt, locateCell, resolveAddress } from "../core/worksheet-core.js";
|
|
4
7
|
import { ExcelError } from "../errors.js";
|
|
5
8
|
/**
|
|
6
9
|
* Resolve the `(ws, addr)` / `(ws, row, col)` reader overload pair.
|
|
@@ -14,6 +17,23 @@ import { ExcelError } from "../errors.js";
|
|
|
14
17
|
function target(ws, addr, col, argc) {
|
|
15
18
|
return argc >= 3 ? getCell(ws, addr, col) : getCell(ws, addr);
|
|
16
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* {@link target} for a reader that answers with a value: resolves the same overload pair and fails on the
|
|
22
|
+
* same malformed references, but never creates the row or the cell — `undefined` when nothing is there,
|
|
23
|
+
* and the reader answers as for an empty cell.
|
|
24
|
+
*
|
|
25
|
+
* A read must not change what the workbook saves — materialising widened `rowCount` and `<dimension>`,
|
|
26
|
+
* and in a styled row or column wrote a styled empty cell into the file. The style-facet readers are the
|
|
27
|
+
* deliberate exception: they hand back the live facet object for the caller to edit in place
|
|
28
|
+
* (`Cell.getStyle(ws, "B2").font = …`), and there is nothing to edit until the cell exists.
|
|
29
|
+
*/
|
|
30
|
+
function peek(ws, addr, col, argc) {
|
|
31
|
+
return argc >= 3 ? locateCell(ws, addr, col) : locateCell(ws, addr);
|
|
32
|
+
}
|
|
33
|
+
/** The overload pair resolved to an address, for a reader that answers from the address alone. */
|
|
34
|
+
function addressOf(ws, addr, col, argc) {
|
|
35
|
+
return argc >= 3 ? resolveAddress(ws, addr, col) : resolveAddress(ws, addr);
|
|
36
|
+
}
|
|
17
37
|
/**
|
|
18
38
|
* {@link target}, for a reader that hands a *style facet* back to the caller.
|
|
19
39
|
*
|
|
@@ -40,14 +60,16 @@ function targetWithValue(ws, addr, valueOrCol, value, argc) {
|
|
|
40
60
|
: [getCell(ws, addr), valueOrCol];
|
|
41
61
|
}
|
|
42
62
|
export function getValue(ws, addr, col) {
|
|
43
|
-
|
|
63
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
64
|
+
return cell ? cellGetValue(cell) : null;
|
|
44
65
|
}
|
|
45
66
|
export function setValue(ws, addr, valueOrCol, value) {
|
|
46
67
|
const [cell, resolved] = targetWithValue(ws, addr, valueOrCol, value, arguments.length);
|
|
47
68
|
cellSetValue(cell, resolved);
|
|
48
69
|
}
|
|
49
70
|
export function getDateParts(ws, addr, col) {
|
|
50
|
-
|
|
71
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
72
|
+
return cell ? cellGetDateParts(cell) : undefined;
|
|
51
73
|
}
|
|
52
74
|
export function setDateParts(ws, addr, partsOrCol, partsOrKind, kind) {
|
|
53
75
|
if (typeof partsOrCol === "number") {
|
|
@@ -57,30 +79,36 @@ export function setDateParts(ws, addr, partsOrCol, partsOrKind, kind) {
|
|
|
57
79
|
cellSetDateParts(getCell(ws, addr), partsOrCol, partsOrKind);
|
|
58
80
|
}
|
|
59
81
|
export function getDateKind(ws, addr, col) {
|
|
60
|
-
|
|
82
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
83
|
+
return cell ? cellDateKind(cell) : undefined;
|
|
61
84
|
}
|
|
62
85
|
export function getTemporal(ws, addr, colOrKind, kind) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
: cellGetTemporal(getCell(ws, addr), colOrKind);
|
|
86
|
+
const cell = typeof colOrKind === "number" ? locateCell(ws, addr, colOrKind) : locateCell(ws, addr);
|
|
87
|
+
return cell ? cellGetTemporal(cell, typeof colOrKind === "number" ? kind : colOrKind) : undefined;
|
|
66
88
|
}
|
|
67
89
|
export function getText(ws, addr, col) {
|
|
68
|
-
|
|
90
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
91
|
+
return cell ? cellText(cell) : "";
|
|
69
92
|
}
|
|
70
93
|
export function getDisplayText(ws, addr, col) {
|
|
71
|
-
|
|
94
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
95
|
+
return cell ? cellDisplayText(cell) : "";
|
|
72
96
|
}
|
|
73
97
|
export function getType(ws, addr, col) {
|
|
74
|
-
|
|
98
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
99
|
+
return cell ? cellType(cell) : ValueType.Null;
|
|
75
100
|
}
|
|
76
101
|
export function getEffectiveType(ws, addr, col) {
|
|
77
|
-
|
|
102
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
103
|
+
return cell ? cellEffectiveType(cell) : ValueType.Null;
|
|
78
104
|
}
|
|
79
105
|
export function getFormula(ws, addr, col) {
|
|
80
|
-
|
|
106
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
107
|
+
return cell ? cellFormula(cell) : undefined;
|
|
81
108
|
}
|
|
82
109
|
export function getResult(ws, addr, col) {
|
|
83
|
-
|
|
110
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
111
|
+
return cell ? cellResult(cell) : undefined;
|
|
84
112
|
}
|
|
85
113
|
export function getStyle(ws, addr, col) {
|
|
86
114
|
return cellOwnStyle(target(ws, addr, col, arguments.length));
|
|
@@ -101,23 +129,28 @@ export function applyCellStyle(ws, addr, nameOrCol, name) {
|
|
|
101
129
|
cellSetStyle(getCell(ws, addr), { styleName });
|
|
102
130
|
}
|
|
103
131
|
export function isMerged(ws, addr, col) {
|
|
104
|
-
|
|
132
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
133
|
+
return cell ? cellIsMerged(cell) : false;
|
|
105
134
|
}
|
|
106
135
|
export function getMergeMaster(ws, addr, col) {
|
|
107
136
|
return cellMaster(target(ws, addr, col, arguments.length));
|
|
108
137
|
}
|
|
109
138
|
export function getHyperlink(ws, addr, col) {
|
|
110
|
-
|
|
139
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
140
|
+
return cell ? cellHyperlink(cell) : undefined;
|
|
111
141
|
}
|
|
112
142
|
export function getNote(ws, addr, col) {
|
|
113
|
-
|
|
143
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
144
|
+
return cell ? cellNote(cell) : undefined;
|
|
114
145
|
}
|
|
115
146
|
export function setNote(ws, addr, noteOrCol, note) {
|
|
116
147
|
const [cell, resolved] = targetWithValue(ws, addr, noteOrCol, note, arguments.length);
|
|
117
148
|
cellSetNote(cell, resolved);
|
|
118
149
|
}
|
|
119
150
|
export function getNames(ws, addr, col) {
|
|
120
|
-
|
|
151
|
+
// Defined names live on the workbook, keyed by address; the cell itself holds none.
|
|
152
|
+
const address = addressOf(ws, addr, col, arguments.length);
|
|
153
|
+
return definedNamesGetNamesEx(getSheetWorkbook(ws)._definedNames, address);
|
|
121
154
|
}
|
|
122
155
|
export function addName(ws, addr, nameOrCol, name) {
|
|
123
156
|
const [cell, resolved] = targetWithValue(ws, addr, nameOrCol, name, arguments.length);
|
|
@@ -139,7 +172,9 @@ export function removeAllNames(ws, addr, col) {
|
|
|
139
172
|
cellRemoveAllNames(target(ws, addr, col, arguments.length));
|
|
140
173
|
}
|
|
141
174
|
export function getValidation(ws, addr, col) {
|
|
142
|
-
|
|
175
|
+
// Validation rules live on the sheet, keyed by address; the cell itself holds none.
|
|
176
|
+
const address = addressOf(ws, addr, col, arguments.length);
|
|
177
|
+
return dataValidationFind(ws.dataValidations, address.address);
|
|
143
178
|
}
|
|
144
179
|
export function setValidation(ws, addr, valueOrCol, value) {
|
|
145
180
|
const [cell, resolved] = targetWithValue(ws, addr, valueOrCol, value, arguments.length);
|
|
@@ -160,7 +195,12 @@ export function setFont(ws, addr, valueOrCol, value) {
|
|
|
160
195
|
cellSetFont(cell, resolved);
|
|
161
196
|
}
|
|
162
197
|
export function getNumFmt(ws, addr, col) {
|
|
163
|
-
|
|
198
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
199
|
+
if (cell) {
|
|
200
|
+
return cellNumFmt(cell);
|
|
201
|
+
}
|
|
202
|
+
const { row, col: column } = addressOf(ws, addr, col, arguments.length);
|
|
203
|
+
return inheritedNumFmt(ws, row, column);
|
|
164
204
|
}
|
|
165
205
|
export function setNumFmt(ws, addr, valueOrCol, value) {
|
|
166
206
|
const [cell, resolved] = targetWithValue(ws, addr, valueOrCol, value, arguments.length);
|
|
@@ -195,7 +235,8 @@ export function setProtection(ws, addr, valueOrCol, value) {
|
|
|
195
235
|
cellSetProtection(cell, resolved);
|
|
196
236
|
}
|
|
197
237
|
export function getComment(ws, addr, col) {
|
|
198
|
-
|
|
238
|
+
const cell = peek(ws, addr, col, arguments.length);
|
|
239
|
+
return cell ? cellComment(cell) : undefined;
|
|
199
240
|
}
|
|
200
241
|
export function setComment(ws, addr, commentOrCol, comment) {
|
|
201
242
|
const [cell, resolved] = targetWithValue(ws, addr, commentOrCol, comment, arguments.length);
|
|
@@ -206,7 +247,7 @@ export function setResult(ws, addr, valueOrCol, value) {
|
|
|
206
247
|
cellSetResult(cell, resolved);
|
|
207
248
|
}
|
|
208
249
|
export function getFullAddress(ws, addr, col) {
|
|
209
|
-
return
|
|
250
|
+
return addressOf(ws, addr, col, arguments.length);
|
|
210
251
|
}
|
|
211
252
|
export function find(ws, addr, col) {
|
|
212
253
|
// Same `argc` discipline as `target`: which overload was called is decided by
|
|
@@ -215,7 +256,7 @@ export function find(ws, addr, col) {
|
|
|
215
256
|
// `(ws, "A1", 99)`; a JavaScript caller that gets past them lands on the
|
|
216
257
|
// (row, col) path and resolves some other address, exactly as every other
|
|
217
258
|
// reader in this namespace does.
|
|
218
|
-
return
|
|
259
|
+
return peek(ws, addr, col, arguments.length);
|
|
219
260
|
}
|
|
220
261
|
/**
|
|
221
262
|
* Read a cell **handle** — the `CellData` handed to `Row.eachCell` /
|
|
@@ -1030,8 +1030,9 @@ export function getCellDisplayText(cell, dateFormat) {
|
|
|
1030
1030
|
typeof value === "string") {
|
|
1031
1031
|
return formatCellValue(value, fmt, dateFormat);
|
|
1032
1032
|
}
|
|
1033
|
-
// Formula type — use the result value
|
|
1034
|
-
|
|
1033
|
+
// Formula type — use the result value. A shared-formula clone carries `sharedFormula` and no `formula`,
|
|
1034
|
+
// and is formatted exactly like the cell that defines it.
|
|
1035
|
+
if (typeof value === "object" && ("formula" in value || "sharedFormula" in value)) {
|
|
1035
1036
|
const result = value.result;
|
|
1036
1037
|
if (result == null) {
|
|
1037
1038
|
return "";
|
|
@@ -21,7 +21,7 @@ import { dataValidationAdd } from "../../core/data-validations.js";
|
|
|
21
21
|
import { definedNamesAdd } from "../../core/defined-names.js";
|
|
22
22
|
import { loadWorkbookModel } from "../../core/model-load.js";
|
|
23
23
|
import { applyPrintName, isPrintName } from "../../core/print-names.js";
|
|
24
|
-
import { createTable, tableSetModel } from "../../core/table.js";
|
|
24
|
+
import { adoptLoadedTotals, createTable, tableSetModel } from "../../core/table.js";
|
|
25
25
|
import { addWorkbookImage, defineCellStyle, getDefinedNames, getWorksheets } from "../../core/workbook-core.js";
|
|
26
26
|
import { addWorksheet, createWorkbook, getWorkbookModel } from "../../core/workbook.browser.js";
|
|
27
27
|
import { addBackgroundImage, mergeCells, getColumn as worksheetColumn, getRow as worksheetRow, setHeaderFooterImage } from "../../core/worksheet.js";
|
|
@@ -734,6 +734,8 @@ async function readInto(workbook, bytes, source, options) {
|
|
|
734
734
|
// the workbook so a second table cannot take it. Assigning the array put an array where a record
|
|
735
735
|
// belonged and `setModel` then threw reading `.name` off an index.
|
|
736
736
|
for (const model of found) {
|
|
737
|
+
// `ref` is the full range here — the XLSB reader has no separate `tableRef`.
|
|
738
|
+
adoptLoadedTotals(worksheet, model, model.tableRef ?? model.ref);
|
|
737
739
|
const handle = createTable(worksheet, model);
|
|
738
740
|
tableSetModel(handle, model);
|
|
739
741
|
worksheet.tables[model.name] = handle;
|
|
@@ -98,11 +98,27 @@ export async function readXlsxInto(workbook, data, options) {
|
|
|
98
98
|
}
|
|
99
99
|
return readXlsxBytesInto(workbook, buffer, options);
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Document-level container defaults. The archive library leaves both bounds
|
|
103
|
+
* unbounded because what a process can afford is host-dependent; a workbook is
|
|
104
|
+
* a narrower thing. A part count of 10,000 mirrors the Word reader's
|
|
105
|
+
* `maxPartCount` and is far above real workbooks (each sheet adds ~2–6 parts:
|
|
106
|
+
* sheet XML, rels, drawing, comments, table), which reach the low hundreds.
|
|
107
|
+
* 2 GiB total sits above what Excel itself can open — sheet XML compresses
|
|
108
|
+
* ~10:1, so this admits a ~200 MB `.xlsx` — while rejecting the many-entries
|
|
109
|
+
* bombs a per-entry bound alone lets through. Pass `Infinity` to lift either.
|
|
110
|
+
*/
|
|
111
|
+
const XLSX_DEFAULT_MAX_ENTRIES = 10000;
|
|
112
|
+
const XLSX_DEFAULT_MAX_TOTAL_UNCOMPRESSED_SIZE = 2 * 1024 * 1024 * 1024;
|
|
101
113
|
/**
|
|
102
114
|
* Internal: Load from Uint8Array buffer
|
|
103
115
|
*/
|
|
104
116
|
export async function readXlsxBytesInto(workbook, buffer, options) {
|
|
105
|
-
const parser = new ZipParser(buffer
|
|
117
|
+
const parser = new ZipParser(buffer, {
|
|
118
|
+
...options?.zip,
|
|
119
|
+
maxEntries: options?.zip?.maxEntries ?? XLSX_DEFAULT_MAX_ENTRIES,
|
|
120
|
+
maxTotalUncompressedSize: options?.zip?.maxTotalUncompressedSize ?? XLSX_DEFAULT_MAX_TOTAL_UNCOMPRESSED_SIZE
|
|
121
|
+
});
|
|
106
122
|
const filesMap = await parser.extractAll();
|
|
107
123
|
// Convert Map to Record for readXlsxFilesInto
|
|
108
124
|
const allFiles = {};
|
|
@@ -1382,7 +1382,9 @@ export class PdfDocumentBuilder {
|
|
|
1382
1382
|
if (snapshot.metadata.title ||
|
|
1383
1383
|
snapshot.metadata.author ||
|
|
1384
1384
|
snapshot.metadata.subject ||
|
|
1385
|
-
snapshot.metadata.creator
|
|
1385
|
+
snapshot.metadata.creator ||
|
|
1386
|
+
snapshot.metadata.creationDate ||
|
|
1387
|
+
snapshot.metadata.modDate) {
|
|
1386
1388
|
writer.addInfoDict(snapshot.metadata);
|
|
1387
1389
|
}
|
|
1388
1390
|
// Encryption
|