@office-kit/xlsx 0.8.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/LICENSE +21 -0
- package/README.md +319 -0
- package/THIRD_PARTY_NOTICES.md +56 -0
- package/dist/cell/cell.d.ts +234 -0
- package/dist/cell/index.d.ts +4 -0
- package/dist/cell/rich-text.d.ts +37 -0
- package/dist/cell-D9CaNKnU.mjs +320 -0
- package/dist/cell-D9CaNKnU.mjs.map +1 -0
- package/dist/cell-style-BEDjMX1y.mjs +1579 -0
- package/dist/cell-style-BEDjMX1y.mjs.map +1 -0
- package/dist/cell.mjs +2 -0
- package/dist/chart/chart-xml.d.ts +16 -0
- package/dist/chart/chart.d.ts +735 -0
- package/dist/chart/cx/chartex-xml.d.ts +6 -0
- package/dist/chart/cx/chartex.d.ts +279 -0
- package/dist/chart/index.d.ts +6 -0
- package/dist/chart/user-shapes-xml.d.ts +4 -0
- package/dist/chart/user-shapes.d.ts +61 -0
- package/dist/chart.mjs +232 -0
- package/dist/chart.mjs.map +1 -0
- package/dist/chartsheet/chartsheet-xml.d.ts +17 -0
- package/dist/chartsheet/chartsheet.d.ts +121 -0
- package/dist/chartsheet/index.d.ts +2 -0
- package/dist/chartsheet-C3-tqkPy.mjs +23 -0
- package/dist/chartsheet-C3-tqkPy.mjs.map +1 -0
- package/dist/chartsheet.mjs +2 -0
- package/dist/colors-ovWAwnZI.mjs +67 -0
- package/dist/colors-ovWAwnZI.mjs.map +1 -0
- package/dist/compat/numbers.d.ts +14 -0
- package/dist/coordinate-96Ecci4d.mjs +276 -0
- package/dist/coordinate-96Ecci4d.mjs.map +1 -0
- package/dist/datetime-B2ySVlXt.mjs +71 -0
- package/dist/datetime-B2ySVlXt.mjs.map +1 -0
- package/dist/defined-names-CviWmtQg.mjs +89 -0
- package/dist/defined-names-CviWmtQg.mjs.map +1 -0
- package/dist/differential-D4dg-qtZ.mjs +37 -0
- package/dist/differential-D4dg-qtZ.mjs.map +1 -0
- package/dist/drawing/anchor.d.ts +63 -0
- package/dist/drawing/dml/colors.d.ts +109 -0
- package/dist/drawing/dml/dml-xml.d.ts +35 -0
- package/dist/drawing/dml/effect.d.ts +92 -0
- package/dist/drawing/dml/fill.d.ts +115 -0
- package/dist/drawing/dml/geometry.d.ts +113 -0
- package/dist/drawing/dml/line.d.ts +41 -0
- package/dist/drawing/dml/shape-properties.d.ts +33 -0
- package/dist/drawing/dml/text.d.ts +218 -0
- package/dist/drawing/drawing-xml.d.ts +5 -0
- package/dist/drawing/drawing.d.ts +117 -0
- package/dist/drawing/image.d.ts +40 -0
- package/dist/drawing/index.d.ts +14 -0
- package/dist/drawing-BxzLuryn.mjs +415 -0
- package/dist/drawing-BxzLuryn.mjs.map +1 -0
- package/dist/drawing.mjs +119 -0
- package/dist/drawing.mjs.map +1 -0
- package/dist/escape-DFTE7ZJc.mjs +51 -0
- package/dist/escape-DFTE7ZJc.mjs.map +1 -0
- package/dist/exceptions-D-CFwxgm.mjs +37 -0
- package/dist/exceptions-D-CFwxgm.mjs.map +1 -0
- package/dist/formula/tokenizer.d.ts +61 -0
- package/dist/formula/translate.d.ts +67 -0
- package/dist/inference-B3ES3KEJ.mjs +42 -0
- package/dist/inference-B3ES3KEJ.mjs.map +1 -0
- package/dist/io/browser.d.ts +41 -0
- package/dist/io/index.d.ts +7 -0
- package/dist/io/load.d.ts +46 -0
- package/dist/io/node-fs.d.ts +62 -0
- package/dist/io/node-save.d.ts +3 -0
- package/dist/io/node.d.ts +17 -0
- package/dist/io/save.d.ts +14 -0
- package/dist/io/sink.d.ts +54 -0
- package/dist/io/source.d.ts +14 -0
- package/dist/io.mjs +212 -0
- package/dist/io.mjs.map +1 -0
- package/dist/load-D5cbhoGx.mjs +1069 -0
- package/dist/load-D5cbhoGx.mjs.map +1 -0
- package/dist/manifest-Dps1-OpP.mjs +801 -0
- package/dist/manifest-Dps1-OpP.mjs.map +1 -0
- package/dist/node.d.ts +3 -0
- package/dist/node.mjs +308 -0
- package/dist/node.mjs.map +1 -0
- package/dist/packaging/core.d.ts +45 -0
- package/dist/packaging/custom.d.ts +62 -0
- package/dist/packaging/extended.d.ts +45 -0
- package/dist/packaging/index.d.ts +10 -0
- package/dist/packaging/manifest.d.ts +24 -0
- package/dist/packaging/relationships.d.ts +30 -0
- package/dist/packaging.mjs +2 -0
- package/dist/parser-DuLejQy1.mjs +156 -0
- package/dist/parser-DuLejQy1.mjs.map +1 -0
- package/dist/reader-D1fNW9k1.mjs +534 -0
- package/dist/reader-D1fNW9k1.mjs.map +1 -0
- package/dist/save-RohQtgEZ.mjs +745 -0
- package/dist/save-RohQtgEZ.mjs.map +1 -0
- package/dist/schema/core.d.ts +133 -0
- package/dist/schema/index.d.ts +3 -0
- package/dist/schema/serialize.d.ts +6 -0
- package/dist/schema.mjs +2 -0
- package/dist/serialize-55EnT30e.mjs +254 -0
- package/dist/serialize-55EnT30e.mjs.map +1 -0
- package/dist/serializer-BwbgHYJV.mjs +116 -0
- package/dist/serializer-BwbgHYJV.mjs.map +1 -0
- package/dist/streaming/index.d.ts +2 -0
- package/dist/streaming/read-only.d.ts +38 -0
- package/dist/streaming/write-only.d.ts +47 -0
- package/dist/streaming.mjs +612 -0
- package/dist/streaming.mjs.map +1 -0
- package/dist/styles/alignment.d.ts +33 -0
- package/dist/styles/alignment.schema.d.ts +3 -0
- package/dist/styles/borders.d.ts +40 -0
- package/dist/styles/borders.schema.d.ts +4 -0
- package/dist/styles/cell-style.d.ts +270 -0
- package/dist/styles/colors.d.ts +128 -0
- package/dist/styles/colors.schema.d.ts +3 -0
- package/dist/styles/differential.d.ts +41 -0
- package/dist/styles/fills.d.ts +54 -0
- package/dist/styles/fills.schema.d.ts +6 -0
- package/dist/styles/fonts.d.ts +44 -0
- package/dist/styles/fonts.schema.d.ts +3 -0
- package/dist/styles/index.d.ts +21 -0
- package/dist/styles/named-styles.d.ts +52 -0
- package/dist/styles/numbers.d.ts +39 -0
- package/dist/styles/numbers.schema.d.ts +3 -0
- package/dist/styles/protection.d.ts +9 -0
- package/dist/styles/protection.schema.d.ts +3 -0
- package/dist/styles/stylesheet-reader.d.ts +7 -0
- package/dist/styles/stylesheet-writer.d.ts +3 -0
- package/dist/styles/stylesheet.d.ts +95 -0
- package/dist/styles.mjs +4 -0
- package/dist/stylesheet-writer-C2eRmn22.mjs +8624 -0
- package/dist/stylesheet-writer-C2eRmn22.mjs.map +1 -0
- package/dist/table-DkX6UniA.mjs +113 -0
- package/dist/table-DkX6UniA.mjs.map +1 -0
- package/dist/tree-Bbs1C8Rc.mjs +192 -0
- package/dist/tree-Bbs1C8Rc.mjs.map +1 -0
- package/dist/units-rOMQqXh2.mjs +41 -0
- package/dist/units-rOMQqXh2.mjs.map +1 -0
- package/dist/user-shapes-DfmCGKB0.mjs +252 -0
- package/dist/user-shapes-DfmCGKB0.mjs.map +1 -0
- package/dist/utf8-D91g1XTG.mjs +143 -0
- package/dist/utf8-D91g1XTG.mjs.map +1 -0
- package/dist/utils/coordinate.d.ts +103 -0
- package/dist/utils/css.d.ts +18 -0
- package/dist/utils/datetime.d.ts +38 -0
- package/dist/utils/escape.d.ts +34 -0
- package/dist/utils/exceptions.d.ts +34 -0
- package/dist/utils/index.d.ts +11 -0
- package/dist/utils/inference.d.ts +24 -0
- package/dist/utils/stable-stringify.d.ts +7 -0
- package/dist/utils/units.d.ts +14 -0
- package/dist/utils/utf8.d.ts +1 -0
- package/dist/utils.mjs +39 -0
- package/dist/utils.mjs.map +1 -0
- package/dist/workbook/calc-properties.d.ts +47 -0
- package/dist/workbook/defined-names.d.ts +121 -0
- package/dist/workbook/file-recovery.d.ts +11 -0
- package/dist/workbook/file-sharing.d.ts +14 -0
- package/dist/workbook/file-version.d.ts +13 -0
- package/dist/workbook/function-groups.d.ts +10 -0
- package/dist/workbook/index.d.ts +24 -0
- package/dist/workbook/protection.d.ts +35 -0
- package/dist/workbook/shared-strings.d.ts +57 -0
- package/dist/workbook/smart-tags.d.ts +13 -0
- package/dist/workbook/views.d.ts +89 -0
- package/dist/workbook/workbook-properties.d.ts +57 -0
- package/dist/workbook/workbook.d.ts +643 -0
- package/dist/workbook-HGYNRBlV.mjs +636 -0
- package/dist/workbook-HGYNRBlV.mjs.map +1 -0
- package/dist/workbook.mjs +58 -0
- package/dist/workbook.mjs.map +1 -0
- package/dist/worksheet/auto-filter.d.ts +34 -0
- package/dist/worksheet/cell-range.d.ts +121 -0
- package/dist/worksheet/comments-xml.d.ts +24 -0
- package/dist/worksheet/comments.d.ts +13 -0
- package/dist/worksheet/conditional-formatting.d.ts +150 -0
- package/dist/worksheet/custom-sheet-views.d.ts +43 -0
- package/dist/worksheet/data-consolidate.d.ts +29 -0
- package/dist/worksheet/data-validations.d.ts +72 -0
- package/dist/worksheet/dimensions.d.ts +40 -0
- package/dist/worksheet/errors.d.ts +40 -0
- package/dist/worksheet/hyperlinks.d.ts +42 -0
- package/dist/worksheet/index.d.ts +46 -0
- package/dist/worksheet/ole-objects.d.ts +37 -0
- package/dist/worksheet/page-setup.d.ts +173 -0
- package/dist/worksheet/phonetic.d.ts +11 -0
- package/dist/worksheet/properties.d.ts +34 -0
- package/dist/worksheet/protected-ranges.d.ts +19 -0
- package/dist/worksheet/protection.d.ts +44 -0
- package/dist/worksheet/reader.d.ts +38 -0
- package/dist/worksheet/scenarios.d.ts +36 -0
- package/dist/worksheet/smart-tags.d.ts +23 -0
- package/dist/worksheet/sort-state.d.ts +28 -0
- package/dist/worksheet/table-xml.d.ts +5 -0
- package/dist/worksheet/table.d.ts +80 -0
- package/dist/worksheet/views.d.ts +47 -0
- package/dist/worksheet/web-publish.d.ts +21 -0
- package/dist/worksheet/worksheet.d.ts +935 -0
- package/dist/worksheet/writer.d.ts +72 -0
- package/dist/worksheet-CmCNoIgD.mjs +1726 -0
- package/dist/worksheet-CmCNoIgD.mjs.map +1 -0
- package/dist/worksheet.mjs +247 -0
- package/dist/worksheet.mjs.map +1 -0
- package/dist/writer-DspzfkNA.mjs +221 -0
- package/dist/writer-DspzfkNA.mjs.map +1 -0
- package/dist/xml/index.d.ts +10 -0
- package/dist/xml/iterparse.d.ts +22 -0
- package/dist/xml/namespaces.d.ts +91 -0
- package/dist/xml/parser.d.ts +7 -0
- package/dist/xml/serializer.d.ts +14 -0
- package/dist/xml/stream-writer.d.ts +39 -0
- package/dist/xml/tree.d.ts +37 -0
- package/dist/xml.mjs +140 -0
- package/dist/xml.mjs.map +1 -0
- package/dist/zip/decompression-guard.d.ts +70 -0
- package/dist/zip/index.d.ts +6 -0
- package/dist/zip/random-access-reader.d.ts +16 -0
- package/dist/zip/reader.d.ts +45 -0
- package/dist/zip/writer.d.ts +65 -0
- package/dist/zip/zip64-patch.d.ts +12 -0
- package/dist/zip.mjs +3 -0
- package/package.json +147 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type SaxEvent = {
|
|
2
|
+
kind: 'start';
|
|
3
|
+
name: string;
|
|
4
|
+
attrs: Record<string, string>;
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'end';
|
|
7
|
+
name: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'text';
|
|
10
|
+
text: string;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Streamable input: `Uint8Array`, plain string, or a Web `ReadableStream` of
|
|
14
|
+
* `Uint8Array` chunks (produced by xlsx zip entries via fflate, fetch, file
|
|
15
|
+
* streams, etc.).
|
|
16
|
+
*/
|
|
17
|
+
export type SaxInput = Uint8Array | string | ReadableStream<Uint8Array>;
|
|
18
|
+
/**
|
|
19
|
+
* Parse the input as a stream of SAX events. Element / attribute names are
|
|
20
|
+
* returned in Clark notation (`{ns}local`).
|
|
21
|
+
*/
|
|
22
|
+
export declare function iterParse(input: SaxInput): AsyncIterableIterator<SaxEvent>;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export declare const XML_NS = "http://www.w3.org/XML/1998/namespace";
|
|
2
|
+
export declare const XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
|
|
3
|
+
export declare const DCORE_NS = "http://purl.org/dc/elements/1.1/";
|
|
4
|
+
export declare const DCTERMS_NS = "http://purl.org/dc/terms/";
|
|
5
|
+
export declare const DCMITYPE_NS = "http://purl.org/dc/dcmitype/";
|
|
6
|
+
export declare const DCTERMS_PREFIX = "dcterms";
|
|
7
|
+
export declare const REL_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
8
|
+
export declare const COMMENTS_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
|
|
9
|
+
export declare const IMAGE_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
|
|
10
|
+
export declare const VML_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing";
|
|
11
|
+
export declare const EXTERNAL_LINK_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink";
|
|
12
|
+
export declare const VTYPES_NS = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes";
|
|
13
|
+
export declare const XPROPS_NS = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
|
|
14
|
+
export declare const CUSTPROPS_NS = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
|
|
15
|
+
export declare const CPROPS_FMTID = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}";
|
|
16
|
+
export declare const PKG_REL_NS = "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
17
|
+
export declare const COREPROPS_NS = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
|
|
18
|
+
export declare const CONTYPES_NS = "http://schemas.openxmlformats.org/package/2006/content-types";
|
|
19
|
+
export declare const SHEET_MAIN_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
|
20
|
+
export declare const CHART_NS = "http://schemas.openxmlformats.org/drawingml/2006/chart";
|
|
21
|
+
export declare const DRAWING_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
|
|
22
|
+
export declare const SHEET_DRAWING_NS = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing";
|
|
23
|
+
export declare const CHART_DRAWING_NS = "http://schemas.openxmlformats.org/drawingml/2006/chartDrawing";
|
|
24
|
+
export declare const PICTURE_NS = "http://schemas.openxmlformats.org/drawingml/2006/picture";
|
|
25
|
+
export declare const CUSTOMUI_NS = "http://schemas.microsoft.com/office/2006/relationships/ui/extensibility";
|
|
26
|
+
export declare const MARKUP_COMPAT_NS = "http://schemas.openxmlformats.org/markup-compatibility/2006";
|
|
27
|
+
export declare const X14_NS = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main";
|
|
28
|
+
export declare const X15_NS = "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main";
|
|
29
|
+
export declare const X16_NS = "http://schemas.microsoft.com/office/spreadsheetml/2014/revision";
|
|
30
|
+
export declare const C14_NS = "http://schemas.microsoft.com/office/drawing/2010/chart";
|
|
31
|
+
export declare const C15_NS = "http://schemas.microsoft.com/office/drawing/2012/chart";
|
|
32
|
+
export declare const C16_NS = "http://schemas.microsoft.com/office/drawing/2017/03/chart";
|
|
33
|
+
export declare const CX_NS = "http://schemas.microsoft.com/office/drawing/2014/chartex";
|
|
34
|
+
export declare const THREADED_COMMENTS_NS = "http://schemas.microsoft.com/office/spreadsheetml/2018/threadedcomments";
|
|
35
|
+
export declare const DEFAULT_PREFIXES: Readonly<Record<string, string>>;
|
|
36
|
+
export declare const PACKAGE_PROPS = "docProps";
|
|
37
|
+
export declare const PACKAGE_XL = "xl";
|
|
38
|
+
export declare const PACKAGE_RELS = "_rels";
|
|
39
|
+
export declare const PACKAGE_THEME = "xl/theme";
|
|
40
|
+
export declare const PACKAGE_WORKSHEETS = "xl/worksheets";
|
|
41
|
+
export declare const PACKAGE_CHARTSHEETS = "xl/chartsheets";
|
|
42
|
+
export declare const PACKAGE_DRAWINGS = "xl/drawings";
|
|
43
|
+
export declare const PACKAGE_CHARTS = "xl/charts";
|
|
44
|
+
export declare const PACKAGE_IMAGES = "xl/media";
|
|
45
|
+
export declare const PACKAGE_PIVOT_TABLE = "xl/pivotTables";
|
|
46
|
+
export declare const PACKAGE_PIVOT_CACHE = "xl/pivotCache";
|
|
47
|
+
export declare const PACKAGE_WORKSHEET_RELS = "xl/worksheets/_rels";
|
|
48
|
+
export declare const PACKAGE_CHARTSHEETS_RELS = "xl/chartsheets/_rels";
|
|
49
|
+
export declare const ARC_CONTENT_TYPES = "[Content_Types].xml";
|
|
50
|
+
export declare const ARC_ROOT_RELS = "_rels/.rels";
|
|
51
|
+
export declare const ARC_WORKBOOK_RELS = "xl/_rels/workbook.xml.rels";
|
|
52
|
+
export declare const ARC_CORE = "docProps/core.xml";
|
|
53
|
+
export declare const ARC_APP = "docProps/app.xml";
|
|
54
|
+
export declare const ARC_CUSTOM = "docProps/custom.xml";
|
|
55
|
+
export declare const ARC_WORKBOOK = "xl/workbook.xml";
|
|
56
|
+
export declare const ARC_STYLE = "xl/styles.xml";
|
|
57
|
+
export declare const ARC_THEME = "xl/theme/theme1.xml";
|
|
58
|
+
export declare const ARC_SHARED_STRINGS = "xl/sharedStrings.xml";
|
|
59
|
+
export declare const ARC_CUSTOM_UI = "customUI/customUI.xml";
|
|
60
|
+
export declare const XLSX_TYPE: string;
|
|
61
|
+
export declare const XLTX_TYPE: string;
|
|
62
|
+
export declare const XLSM_TYPE: string;
|
|
63
|
+
export declare const XLTM_TYPE: string;
|
|
64
|
+
export declare const SHARED_STRINGS_TYPE: string;
|
|
65
|
+
export declare const EXTERNAL_LINK_TYPE: string;
|
|
66
|
+
export declare const WORKSHEET_TYPE: string;
|
|
67
|
+
export declare const COMMENTS_TYPE: string;
|
|
68
|
+
export declare const STYLES_TYPE: string;
|
|
69
|
+
export declare const CHARTSHEET_TYPE: string;
|
|
70
|
+
export declare const DRAWING_TYPE = "application/vnd.openxmlformats-officedocument.drawing+xml";
|
|
71
|
+
export declare const CHART_TYPE = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml";
|
|
72
|
+
export declare const CHARTEX_TYPE = "application/vnd.ms-office.chartex+xml";
|
|
73
|
+
export declare const CHARTSHAPE_TYPE = "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml";
|
|
74
|
+
export declare const THEME_TYPE = "application/vnd.openxmlformats-officedocument.theme+xml";
|
|
75
|
+
export declare const CPROPS_TYPE = "application/vnd.openxmlformats-officedocument.custom-properties+xml";
|
|
76
|
+
export declare const VBA_TYPE = "application/vnd.ms-office.vbaProject";
|
|
77
|
+
export declare const ACTIVEX_TYPE = "application/vnd.ms-office.activeX+xml";
|
|
78
|
+
export declare const CTRLPROPS_TYPE = "application/vnd.ms-excel.controlproperties+xml";
|
|
79
|
+
/**
|
|
80
|
+
* Build a Clark-notation QName: `{namespace}localname`. When `namespace` is
|
|
81
|
+
* empty / undefined the local name is returned as-is.
|
|
82
|
+
*/
|
|
83
|
+
export declare function qname(namespace: string | undefined, local: string): string;
|
|
84
|
+
/**
|
|
85
|
+
* Inverse of {@link qname}. Returns `{ ns, local }`. For unprefixed names `ns`
|
|
86
|
+
* is the empty string.
|
|
87
|
+
*/
|
|
88
|
+
export declare function parseQName(name: string): {
|
|
89
|
+
ns: string;
|
|
90
|
+
local: string;
|
|
91
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type XmlNode } from './tree';
|
|
2
|
+
/**
|
|
3
|
+
* Parse a UTF-8 XML payload into an {@link XmlNode} tree. Element and attribute
|
|
4
|
+
* names are returned in Clark notation. Throws {@link OpenXmlSchemaError} on
|
|
5
|
+
* DTD/entity declarations or on multi-root documents.
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseXml(input: Uint8Array | string): XmlNode;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { XmlNode } from './tree';
|
|
2
|
+
export interface SerializeOptions {
|
|
3
|
+
/** Emit `<?xml … ?>` declaration. Defaults to true. */
|
|
4
|
+
xmlDeclaration?: boolean;
|
|
5
|
+
/** `standalone` attribute on the declaration. Defaults to 'yes'. */
|
|
6
|
+
standalone?: 'yes' | 'no' | 'omit';
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Serialize an {@link XmlNode} tree into a UTF-8 byte payload. The
|
|
10
|
+
* inverse of {@link parseXml}: `parseXml(serializeXml(n))` yields a
|
|
11
|
+
* tree structurally equivalent to `n` modulo attribute insertion order
|
|
12
|
+
* (which both directions preserve on Node 18+ / V8).
|
|
13
|
+
*/
|
|
14
|
+
export declare function serializeXml(root: XmlNode, opts?: SerializeOptions): Uint8Array;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { XmlNode } from './tree';
|
|
2
|
+
export interface XmlStreamWriterOptions {
|
|
3
|
+
/** Map of namespace URI → prefix. Merged on top of DEFAULT_PREFIXES. */
|
|
4
|
+
prefixMap?: Readonly<Record<string, string>>;
|
|
5
|
+
/** Emit `<?xml … ?>` declaration first. Defaults to true. */
|
|
6
|
+
xmlDeclaration?: boolean;
|
|
7
|
+
/** `standalone` attribute on the declaration. Defaults to 'yes'. */
|
|
8
|
+
standalone?: 'yes' | 'no' | 'omit';
|
|
9
|
+
/**
|
|
10
|
+
* Auto-flush threshold in bytes. Once the in-flight string buffer crosses
|
|
11
|
+
* this size it gets encoded into a chunk and parked. Larger values trade
|
|
12
|
+
* memory for fewer TextEncoder calls; smaller values lower peak memory at the
|
|
13
|
+
* cost of CPU.
|
|
14
|
+
*/
|
|
15
|
+
flushBytes?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface XmlStreamWriter {
|
|
18
|
+
/**
|
|
19
|
+
* Open an element. Names are in Clark notation (`{ns}local`); the writer
|
|
20
|
+
* prefixes them via the configured prefix map.
|
|
21
|
+
*/
|
|
22
|
+
start(name: string, attrs?: Record<string, string>): void;
|
|
23
|
+
/** Emit a text node inside the currently open element. */
|
|
24
|
+
text(s: string): void;
|
|
25
|
+
/** Emit a complete subtree. Closes any pending start tag first. */
|
|
26
|
+
writeNode(n: XmlNode): void;
|
|
27
|
+
/** Emit pre-rendered XML bytes verbatim — escape-hatch for hot paths. */
|
|
28
|
+
writeRaw(s: string): void;
|
|
29
|
+
/** Close the currently open element (matched against the start stack). */
|
|
30
|
+
end(): void;
|
|
31
|
+
/** Force any buffered bytes into the chunk store immediately. */
|
|
32
|
+
flush(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Materialise everything written so far. Throws if any element is still open.
|
|
35
|
+
* Idempotent.
|
|
36
|
+
*/
|
|
37
|
+
result(): Uint8Array;
|
|
38
|
+
}
|
|
39
|
+
export declare function createXmlStreamWriter(opts?: XmlStreamWriterOptions): XmlStreamWriter;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface XmlNode {
|
|
2
|
+
/** Clark-notation qualified name: `{namespace}local` or just `local`. */
|
|
3
|
+
name: string;
|
|
4
|
+
/** Attribute table; values are always strings (no value coercion at this layer). */
|
|
5
|
+
attrs: Record<string, string>;
|
|
6
|
+
/**
|
|
7
|
+
* Optional element text. When an element has both text and child elements,
|
|
8
|
+
* callers should set `text` and rely on `children` for mixed content; the
|
|
9
|
+
* serializer emits `text` then children.
|
|
10
|
+
*/
|
|
11
|
+
text?: string;
|
|
12
|
+
/** Child element nodes in document order. */
|
|
13
|
+
children: XmlNode[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Build an XmlNode from primitive bits. Attributes / children default to empty;
|
|
17
|
+
* pass `undefined` for `text` to omit the text node.
|
|
18
|
+
*
|
|
19
|
+
* The element's name is always supplied in Clark notation. Use the {@link
|
|
20
|
+
* qname} helper from `./namespaces` to keep call sites readable.
|
|
21
|
+
*/
|
|
22
|
+
export declare function el(name: string, attrs?: Readonly<Record<string, string | number | boolean | null | undefined>>, children?: ReadonlyArray<XmlNode>, text?: string): XmlNode;
|
|
23
|
+
/**
|
|
24
|
+
* Convenience: element with a Clark-notation name composed from a namespace URI
|
|
25
|
+
* and local name.
|
|
26
|
+
*/
|
|
27
|
+
export declare function elNs(namespace: string | undefined, local: string, attrs?: Readonly<Record<string, string | number | boolean | null | undefined>>, children?: ReadonlyArray<XmlNode>, text?: string): XmlNode;
|
|
28
|
+
/** Locate the first child matching the supplied Clark-notation name. */
|
|
29
|
+
export declare function findChild(node: XmlNode, name: string): XmlNode | undefined;
|
|
30
|
+
/** All children matching the supplied Clark-notation name, in document order. */
|
|
31
|
+
export declare function findChildren(node: XmlNode, name: string): XmlNode[];
|
|
32
|
+
/**
|
|
33
|
+
* Append `child` to `parent`. Mutates and returns `parent` for chaining during
|
|
34
|
+
* construction. Avoid in hot paths — for cell writing the worksheet writer goes
|
|
35
|
+
* through a templated emitter rather than building XmlNode trees per cell.
|
|
36
|
+
*/
|
|
37
|
+
export declare function appendChild(parent: XmlNode, child: XmlNode): XmlNode;
|
package/dist/xml.mjs
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { i as OpenXmlIoError } from "./exceptions-D-CFwxgm.mjs";
|
|
2
|
+
import { n as escapeXmlAttr, r as escapeXmlText } from "./escape-DFTE7ZJc.mjs";
|
|
3
|
+
import { $ as PACKAGE_PIVOT_CACHE, A as COREPROPS_NS, At as parseQName, B as DCTERMS_PREFIX, C as CHARTSHEET_TYPE, Ct as XLSM_TYPE, D as COMMENTS_NS, Dt as XML_NS, E as CHART_TYPE, Et as XLTX_TYPE, F as CUSTPROPS_NS, G as EXTERNAL_LINK_TYPE, H as DRAWING_NS, I as CX_NS, J as PACKAGE_CHARTS, K as IMAGE_NS, L as DCMITYPE_NS, M as CPROPS_TYPE, N as CTRLPROPS_TYPE, O as COMMENTS_TYPE, Ot as XPROPS_NS, P as CUSTOMUI_NS, Q as PACKAGE_IMAGES, R as DCORE_NS, S as CHARTSHAPE_TYPE, St as X16_NS, T as CHART_NS, Tt as XLTM_TYPE, U as DRAWING_TYPE, V as DEFAULT_PREFIXES, W as EXTERNAL_LINK_NS, X as PACKAGE_CHARTSHEETS_RELS, Y as PACKAGE_CHARTSHEETS, Z as PACKAGE_DRAWINGS, _ as ARC_WORKBOOK_RELS, _t as VML_NS, a as findChildren, at as PACKAGE_WORKSHEET_RELS, b as C16_NS, bt as X14_NS, c as ARC_CONTENT_TYPES, ct as PKG_REL_NS, d as ARC_CUSTOM_UI, dt as SHEET_DRAWING_NS, et as PACKAGE_PIVOT_TABLE, f as ARC_ROOT_RELS, ft as SHEET_MAIN_NS, g as ARC_WORKBOOK, gt as VBA_TYPE, h as ARC_THEME, ht as THREADED_COMMENTS_NS, i as findChild, it as PACKAGE_WORKSHEETS, j as CPROPS_FMTID, jt as qname, k as CONTYPES_NS, kt as XSI_NS, l as ARC_CORE, lt as REL_NS, m as ARC_STYLE, mt as THEME_TYPE, n as el, nt as PACKAGE_RELS, o as ACTIVEX_TYPE, ot as PACKAGE_XL, p as ARC_SHARED_STRINGS, pt as STYLES_TYPE, q as MARKUP_COMPAT_NS, r as elNs, rt as PACKAGE_THEME, s as ARC_APP, st as PICTURE_NS, t as appendChild, tt as PACKAGE_PROPS, u as ARC_CUSTOM, ut as SHARED_STRINGS_TYPE, v as C14_NS, vt as VTYPES_NS, w as CHART_DRAWING_NS, wt as XLSX_TYPE, xt as X15_NS, y as C15_NS, yt as WORKSHEET_TYPE, z as DCTERMS_NS } from "./tree-Bbs1C8Rc.mjs";
|
|
4
|
+
import { t as parseXml } from "./parser-DuLejQy1.mjs";
|
|
5
|
+
import { t as serializeXml } from "./serializer-BwbgHYJV.mjs";
|
|
6
|
+
import { n as iterParse, t as utf8ByteLength } from "./utf8-D91g1XTG.mjs";
|
|
7
|
+
//#region src/xml/stream-writer.ts
|
|
8
|
+
const DEFAULT_FLUSH_BYTES = 64 * 1024;
|
|
9
|
+
const encoder = new TextEncoder();
|
|
10
|
+
const buildPrefixMap = (user) => {
|
|
11
|
+
const out = /* @__PURE__ */ new Map();
|
|
12
|
+
for (const [ns, prefix] of Object.entries(DEFAULT_PREFIXES)) out.set(ns, prefix);
|
|
13
|
+
out.set(XML_NS, "xml");
|
|
14
|
+
if (user !== void 0) for (const [ns, prefix] of Object.entries(user)) out.set(ns, prefix);
|
|
15
|
+
return out;
|
|
16
|
+
};
|
|
17
|
+
function createXmlStreamWriter(opts = {}) {
|
|
18
|
+
const { xmlDeclaration = true, standalone = "yes", flushBytes = DEFAULT_FLUSH_BYTES } = opts;
|
|
19
|
+
const prefixOf = buildPrefixMap(opts.prefixMap);
|
|
20
|
+
const chunks = [];
|
|
21
|
+
let buf = "";
|
|
22
|
+
let bufBytes = 0;
|
|
23
|
+
let openStartTag = false;
|
|
24
|
+
let finalised = false;
|
|
25
|
+
const stack = [];
|
|
26
|
+
const append = (s) => {
|
|
27
|
+
buf += s;
|
|
28
|
+
bufBytes += utf8ByteLength(s);
|
|
29
|
+
};
|
|
30
|
+
const elementName = (name) => {
|
|
31
|
+
const { ns, local } = parseQName(name);
|
|
32
|
+
if (ns === "") return local;
|
|
33
|
+
const prefix = prefixOf.get(ns);
|
|
34
|
+
if (prefix === void 0 || prefix === "") return local;
|
|
35
|
+
return `${prefix}:${local}`;
|
|
36
|
+
};
|
|
37
|
+
const attributeName = (name) => {
|
|
38
|
+
const { ns, local } = parseQName(name);
|
|
39
|
+
if (ns === "") return local;
|
|
40
|
+
const prefix = prefixOf.get(ns);
|
|
41
|
+
if (prefix === void 0 || prefix === "") return local;
|
|
42
|
+
return `${prefix}:${local}`;
|
|
43
|
+
};
|
|
44
|
+
const flushImpl = () => {
|
|
45
|
+
if (buf.length === 0) return;
|
|
46
|
+
chunks.push(encoder.encode(buf));
|
|
47
|
+
buf = "";
|
|
48
|
+
bufBytes = 0;
|
|
49
|
+
};
|
|
50
|
+
const maybeFlush = () => {
|
|
51
|
+
if (bufBytes >= flushBytes) flushImpl();
|
|
52
|
+
};
|
|
53
|
+
const closeStartTagIfOpen = () => {
|
|
54
|
+
if (!openStartTag) return;
|
|
55
|
+
append(">");
|
|
56
|
+
openStartTag = false;
|
|
57
|
+
};
|
|
58
|
+
if (xmlDeclaration) {
|
|
59
|
+
append("<?xml version=\"1.0\" encoding=\"UTF-8\"");
|
|
60
|
+
if (standalone !== "omit") append(` standalone="${standalone}"`);
|
|
61
|
+
append("?>\n");
|
|
62
|
+
}
|
|
63
|
+
const emitNodeInline = (n) => {
|
|
64
|
+
const tag = elementName(n.name);
|
|
65
|
+
append(`<${tag}`);
|
|
66
|
+
for (const [name, value] of Object.entries(n.attrs)) append(` ${attributeName(name)}="${escapeXmlAttr(value)}"`);
|
|
67
|
+
const text = n.text;
|
|
68
|
+
const hasText = text !== void 0 && text !== "";
|
|
69
|
+
const hasChildren = n.children.length > 0;
|
|
70
|
+
if (!hasText && !hasChildren) {
|
|
71
|
+
append("/>");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
append(">");
|
|
75
|
+
if (hasText) append(escapeXmlText(text));
|
|
76
|
+
for (const c of n.children) emitNodeInline(c);
|
|
77
|
+
append(`</${tag}>`);
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
start(name, attrs) {
|
|
81
|
+
if (finalised) throw new OpenXmlIoError("XmlStreamWriter: start() after result()");
|
|
82
|
+
closeStartTagIfOpen();
|
|
83
|
+
const tag = elementName(name);
|
|
84
|
+
append(`<${tag}`);
|
|
85
|
+
if (attrs !== void 0) for (const [k, v] of Object.entries(attrs)) append(` ${attributeName(k)}="${escapeXmlAttr(v)}"`);
|
|
86
|
+
stack.push(tag);
|
|
87
|
+
openStartTag = true;
|
|
88
|
+
maybeFlush();
|
|
89
|
+
},
|
|
90
|
+
text(s) {
|
|
91
|
+
if (finalised) throw new OpenXmlIoError("XmlStreamWriter: text() after result()");
|
|
92
|
+
closeStartTagIfOpen();
|
|
93
|
+
append(escapeXmlText(s));
|
|
94
|
+
maybeFlush();
|
|
95
|
+
},
|
|
96
|
+
writeNode(n) {
|
|
97
|
+
if (finalised) throw new OpenXmlIoError("XmlStreamWriter: writeNode() after result()");
|
|
98
|
+
closeStartTagIfOpen();
|
|
99
|
+
emitNodeInline(n);
|
|
100
|
+
maybeFlush();
|
|
101
|
+
},
|
|
102
|
+
writeRaw(s) {
|
|
103
|
+
if (finalised) throw new OpenXmlIoError("XmlStreamWriter: writeRaw() after result()");
|
|
104
|
+
closeStartTagIfOpen();
|
|
105
|
+
append(s);
|
|
106
|
+
maybeFlush();
|
|
107
|
+
},
|
|
108
|
+
end() {
|
|
109
|
+
if (finalised) throw new OpenXmlIoError("XmlStreamWriter: end() after result()");
|
|
110
|
+
const tag = stack.pop();
|
|
111
|
+
if (tag === void 0) throw new OpenXmlIoError("XmlStreamWriter: end() with no open element");
|
|
112
|
+
if (openStartTag) {
|
|
113
|
+
append("/>");
|
|
114
|
+
openStartTag = false;
|
|
115
|
+
} else append(`</${tag}>`);
|
|
116
|
+
maybeFlush();
|
|
117
|
+
},
|
|
118
|
+
flush() {
|
|
119
|
+
flushImpl();
|
|
120
|
+
},
|
|
121
|
+
result() {
|
|
122
|
+
if (stack.length > 0) throw new OpenXmlIoError(`XmlStreamWriter: ${stack.length} unclosed element(s) at result()`);
|
|
123
|
+
flushImpl();
|
|
124
|
+
finalised = true;
|
|
125
|
+
let total = 0;
|
|
126
|
+
for (const c of chunks) total += c.byteLength;
|
|
127
|
+
const out = new Uint8Array(total);
|
|
128
|
+
let off = 0;
|
|
129
|
+
for (const c of chunks) {
|
|
130
|
+
out.set(c, off);
|
|
131
|
+
off += c.byteLength;
|
|
132
|
+
}
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
//#endregion
|
|
138
|
+
export { ACTIVEX_TYPE, ARC_APP, ARC_CONTENT_TYPES, ARC_CORE, ARC_CUSTOM, ARC_CUSTOM_UI, ARC_ROOT_RELS, ARC_SHARED_STRINGS, ARC_STYLE, ARC_THEME, ARC_WORKBOOK, ARC_WORKBOOK_RELS, C14_NS, C15_NS, C16_NS, CHARTSHAPE_TYPE, CHARTSHEET_TYPE, CHART_DRAWING_NS, CHART_NS, CHART_TYPE, COMMENTS_NS, COMMENTS_TYPE, CONTYPES_NS, COREPROPS_NS, CPROPS_FMTID, CPROPS_TYPE, CTRLPROPS_TYPE, CUSTOMUI_NS, CUSTPROPS_NS, CX_NS, DCMITYPE_NS, DCORE_NS, DCTERMS_NS, DCTERMS_PREFIX, DEFAULT_PREFIXES, DRAWING_NS, DRAWING_TYPE, EXTERNAL_LINK_NS, EXTERNAL_LINK_TYPE, IMAGE_NS, MARKUP_COMPAT_NS, PACKAGE_CHARTS, PACKAGE_CHARTSHEETS, PACKAGE_CHARTSHEETS_RELS, PACKAGE_DRAWINGS, PACKAGE_IMAGES, PACKAGE_PIVOT_CACHE, PACKAGE_PIVOT_TABLE, PACKAGE_PROPS, PACKAGE_RELS, PACKAGE_THEME, PACKAGE_WORKSHEETS, PACKAGE_WORKSHEET_RELS, PACKAGE_XL, PICTURE_NS, PKG_REL_NS, REL_NS, SHARED_STRINGS_TYPE, SHEET_DRAWING_NS, SHEET_MAIN_NS, STYLES_TYPE, THEME_TYPE, THREADED_COMMENTS_NS, VBA_TYPE, VML_NS, VTYPES_NS, WORKSHEET_TYPE, X14_NS, X15_NS, X16_NS, XLSM_TYPE, XLSX_TYPE, XLTM_TYPE, XLTX_TYPE, XML_NS, XPROPS_NS, XSI_NS, appendChild, createXmlStreamWriter, el, elNs, findChild, findChildren, iterParse, parseQName, parseXml, qname, serializeXml };
|
|
139
|
+
|
|
140
|
+
//# sourceMappingURL=xml.mjs.map
|
package/dist/xml.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xml.mjs","names":[],"sources":["../src/xml/stream-writer.ts"],"sourcesContent":["// Streaming XML emitter. Used by writers that need to compose larger documents\n// incrementally — chiefly the worksheet writer where the `<sheetData>` block is\n// emitted row-by-row to keep heap use bounded.\n//\n// Phase 1 §5: buffered output only (a chunk array materialised on `result()`).\n// Streaming via `WritableStream<Uint8Array>` is added in the phase-4 streaming\n// worksheet writer; the structural API stays the same so that change is\n// mechanical.\n//\n// The worksheet hot path emits cells through templated strings, NOT through\n// this writer's start / end / writeNode methods. Use `writeRaw` to splice those\n// in.\n\nimport { escapeXmlAttr, escapeXmlText } from '../utils/escape';\nimport { OpenXmlIoError } from '../utils/exceptions';\nimport { utf8ByteLength } from '../utils/utf8';\nimport { DEFAULT_PREFIXES, parseQName, XML_NS } from './namespaces';\nimport type { XmlNode } from './tree';\n\nexport interface XmlStreamWriterOptions {\n /** Map of namespace URI → prefix. Merged on top of DEFAULT_PREFIXES. */\n prefixMap?: Readonly<Record<string, string>>;\n /** Emit `<?xml … ?>` declaration first. Defaults to true. */\n xmlDeclaration?: boolean;\n /** `standalone` attribute on the declaration. Defaults to 'yes'. */\n standalone?: 'yes' | 'no' | 'omit';\n /**\n * Auto-flush threshold in bytes. Once the in-flight string buffer crosses\n * this size it gets encoded into a chunk and parked. Larger values trade\n * memory for fewer TextEncoder calls; smaller values lower peak memory at the\n * cost of CPU.\n */\n flushBytes?: number;\n}\n\nexport interface XmlStreamWriter {\n /**\n * Open an element. Names are in Clark notation (`{ns}local`); the writer\n * prefixes them via the configured prefix map.\n */\n start(name: string, attrs?: Record<string, string>): void;\n /** Emit a text node inside the currently open element. */\n text(s: string): void;\n /** Emit a complete subtree. Closes any pending start tag first. */\n writeNode(n: XmlNode): void;\n /** Emit pre-rendered XML bytes verbatim — escape-hatch for hot paths. */\n writeRaw(s: string): void;\n /** Close the currently open element (matched against the start stack). */\n end(): void;\n /** Force any buffered bytes into the chunk store immediately. */\n flush(): void;\n /**\n * Materialise everything written so far. Throws if any element is still open.\n * Idempotent.\n */\n result(): Uint8Array;\n}\n\nconst DEFAULT_FLUSH_BYTES = 64 * 1024;\nconst encoder = new TextEncoder();\n\nconst buildPrefixMap = (user: Readonly<Record<string, string>> | undefined): Map<string, string> => {\n const out = new Map<string, string>();\n for (const [ns, prefix] of Object.entries(DEFAULT_PREFIXES)) out.set(ns, prefix);\n // The xml prefix is reserved by the XMLNS spec for XML_NS; never override.\n out.set(XML_NS, 'xml');\n if (user !== undefined) {\n for (const [ns, prefix] of Object.entries(user)) out.set(ns, prefix);\n }\n return out;\n};\n\nexport function createXmlStreamWriter(opts: XmlStreamWriterOptions = {}): XmlStreamWriter {\n const { xmlDeclaration = true, standalone = 'yes', flushBytes = DEFAULT_FLUSH_BYTES } = opts;\n const prefixOf = buildPrefixMap(opts.prefixMap);\n\n const chunks: Uint8Array[] = [];\n let buf = '';\n // Running UTF-8 byte count of `buf`, maintained incrementally via `append()`.\n // Without this the flush threshold compares UTF-16 code units against a\n // byte budget — non-ASCII payloads then balloon past the configured limit.\n let bufBytes = 0;\n let openStartTag = false;\n let finalised = false;\n const stack: string[] = [];\n\n const append = (s: string): void => {\n buf += s;\n bufBytes += utf8ByteLength(s);\n };\n\n const elementName = (name: string): string => {\n const { ns, local } = parseQName(name);\n if (ns === '') return local;\n const prefix = prefixOf.get(ns);\n if (prefix === undefined || prefix === '') return local;\n return `${prefix}:${local}`;\n };\n const attributeName = (name: string): string => {\n const { ns, local } = parseQName(name);\n if (ns === '') return local;\n const prefix = prefixOf.get(ns);\n if (prefix === undefined || prefix === '') return local;\n return `${prefix}:${local}`;\n };\n\n const flushImpl = (): void => {\n if (buf.length === 0) return;\n chunks.push(encoder.encode(buf));\n buf = '';\n bufBytes = 0;\n };\n\n const maybeFlush = (): void => {\n if (bufBytes >= flushBytes) flushImpl();\n };\n\n const closeStartTagIfOpen = (): void => {\n if (!openStartTag) return;\n append('>');\n openStartTag = false;\n };\n\n if (xmlDeclaration) {\n append('<?xml version=\"1.0\" encoding=\"UTF-8\"');\n if (standalone !== 'omit') append(` standalone=\"${standalone}\"`);\n append('?>\\n');\n }\n\n // ---- writeNode internals\n // ---------------------------------------------------\n\n const emitNodeInline = (n: XmlNode): void => {\n const tag = elementName(n.name);\n append(`<${tag}`);\n for (const [name, value] of Object.entries(n.attrs)) {\n append(` ${attributeName(name)}=\"${escapeXmlAttr(value)}\"`);\n }\n const text = n.text;\n const hasText = text !== undefined && text !== '';\n const hasChildren = n.children.length > 0;\n if (!hasText && !hasChildren) {\n append('/>');\n return;\n }\n append('>');\n if (hasText) append(escapeXmlText(text));\n for (const c of n.children) emitNodeInline(c);\n append(`</${tag}>`);\n };\n\n // ---- public surface\n // --------------------------------------------------------\n\n return {\n start(name, attrs) {\n if (finalised) throw new OpenXmlIoError('XmlStreamWriter: start() after result()');\n closeStartTagIfOpen();\n const tag = elementName(name);\n append(`<${tag}`);\n if (attrs !== undefined) {\n for (const [k, v] of Object.entries(attrs)) {\n append(` ${attributeName(k)}=\"${escapeXmlAttr(v)}\"`);\n }\n }\n stack.push(tag);\n openStartTag = true;\n maybeFlush();\n },\n text(s) {\n if (finalised) throw new OpenXmlIoError('XmlStreamWriter: text() after result()');\n closeStartTagIfOpen();\n append(escapeXmlText(s));\n maybeFlush();\n },\n writeNode(n) {\n if (finalised) throw new OpenXmlIoError('XmlStreamWriter: writeNode() after result()');\n closeStartTagIfOpen();\n emitNodeInline(n);\n maybeFlush();\n },\n writeRaw(s) {\n if (finalised) throw new OpenXmlIoError('XmlStreamWriter: writeRaw() after result()');\n closeStartTagIfOpen();\n append(s);\n maybeFlush();\n },\n end() {\n if (finalised) throw new OpenXmlIoError('XmlStreamWriter: end() after result()');\n const tag = stack.pop();\n if (tag === undefined) throw new OpenXmlIoError('XmlStreamWriter: end() with no open element');\n if (openStartTag) {\n append('/>');\n openStartTag = false;\n } else {\n append(`</${tag}>`);\n }\n maybeFlush();\n },\n flush() {\n flushImpl();\n },\n result(): Uint8Array {\n if (stack.length > 0) {\n throw new OpenXmlIoError(`XmlStreamWriter: ${stack.length} unclosed element(s) at result()`);\n }\n flushImpl();\n finalised = true;\n let total = 0;\n for (const c of chunks) total += c.byteLength;\n const out = new Uint8Array(total);\n let off = 0;\n for (const c of chunks) {\n out.set(c, off);\n off += c.byteLength;\n }\n return out;\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { OpenXmlDecompressionBombError } from '../utils/exceptions';
|
|
2
|
+
/** Per-archive limits enforced during {@link openZip}. */
|
|
3
|
+
export interface DecompressionLimits {
|
|
4
|
+
/**
|
|
5
|
+
* Maximum decompressed bytes for a single archive entry. Default 512 MiB.
|
|
6
|
+
* Legitimate xlsx sheets stay well below this even with millions of cells.
|
|
7
|
+
*/
|
|
8
|
+
maxEntryUncompressedBytes?: number;
|
|
9
|
+
/**
|
|
10
|
+
* Maximum decompressed bytes summed across every entry the caller reads.
|
|
11
|
+
* Default 1 GiB.
|
|
12
|
+
*/
|
|
13
|
+
maxTotalUncompressedBytes?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Maximum allowed `uncompressed / compressed` ratio for a single entry.
|
|
16
|
+
* Default 1000. xml usually compresses 5–20×, but highly repetitive payloads
|
|
17
|
+
* (long runs of zeros, sparse worksheets) can hit several hundred ×
|
|
18
|
+
* legitimately. Classic zip-bombs run 10 000× and up, so a 1000× ceiling
|
|
19
|
+
* still catches them while admitting realistic content. The implementation
|
|
20
|
+
* treats compressed sizes below 64 B as exempt — there's no amplification
|
|
21
|
+
* budget worth policing on such small entries, and the absolute per-entry /
|
|
22
|
+
* archive limits already cover them.
|
|
23
|
+
*/
|
|
24
|
+
maxCompressionRatio?: number;
|
|
25
|
+
}
|
|
26
|
+
/** Resolved limits with no `undefined` fields. */
|
|
27
|
+
export interface ResolvedDecompressionLimits {
|
|
28
|
+
readonly maxEntryUncompressedBytes: number;
|
|
29
|
+
readonly maxTotalUncompressedBytes: number;
|
|
30
|
+
readonly maxCompressionRatio: number;
|
|
31
|
+
}
|
|
32
|
+
/** Default safeguards applied when the caller doesn't override them. */
|
|
33
|
+
export declare const DEFAULT_DECOMPRESSION_LIMITS: ResolvedDecompressionLimits;
|
|
34
|
+
/**
|
|
35
|
+
* `DecompressionLimits` plus the sentinel `false` to disable the guard.
|
|
36
|
+
* Anything else is treated as "use defaults".
|
|
37
|
+
*/
|
|
38
|
+
export type DecompressionLimitsInput = DecompressionLimits | false | undefined;
|
|
39
|
+
/** Returns null when the guard is disabled. */
|
|
40
|
+
export declare function resolveDecompressionLimits(input: DecompressionLimitsInput): ResolvedDecompressionLimits | null;
|
|
41
|
+
/**
|
|
42
|
+
* Per-archive byte accounting shared across every read of an archive opened
|
|
43
|
+
* with the given limits. Tracks total inflated bytes so the cap is enforced
|
|
44
|
+
* even when individual entries stay below the per-entry ceiling.
|
|
45
|
+
*/
|
|
46
|
+
export interface DecompressionBudget {
|
|
47
|
+
readonly limits: ResolvedDecompressionLimits;
|
|
48
|
+
totalInflated: number;
|
|
49
|
+
}
|
|
50
|
+
export declare function createBudget(limits: ResolvedDecompressionLimits): DecompressionBudget;
|
|
51
|
+
/**
|
|
52
|
+
* Per-entry inflate cap, accounting for both the absolute per-entry bound and
|
|
53
|
+
* the ratio-based bound. Returns the smaller of the two — whichever fires
|
|
54
|
+
* first stops the inflate loop.
|
|
55
|
+
*/
|
|
56
|
+
export declare function entryInflateCap(budget: DecompressionBudget, compressedSize: number): number;
|
|
57
|
+
/** Throw if the declared central-directory totals already exceed the limits. */
|
|
58
|
+
export declare function checkDeclaredTotals(budget: DecompressionBudget, declaredEntries: ReadonlyArray<{
|
|
59
|
+
path: string;
|
|
60
|
+
compSize: number;
|
|
61
|
+
uncompSize: number;
|
|
62
|
+
}>): void;
|
|
63
|
+
/**
|
|
64
|
+
* Record `bytes` against the global budget. Throws when the running total
|
|
65
|
+
* crosses {@link ResolvedDecompressionLimits.maxTotalUncompressedBytes}. Called
|
|
66
|
+
* from both sync and streaming inflate code paths.
|
|
67
|
+
*/
|
|
68
|
+
export declare function recordInflated(budget: DecompressionBudget, path: string, bytes: number): void;
|
|
69
|
+
/** Build the message thrown when a single entry exceeds its cap mid-inflate. */
|
|
70
|
+
export declare function entryOverflowError(path: string, cap: number): OpenXmlDecompressionBombError;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { DecompressionLimits, ResolvedDecompressionLimits, } from './decompression-guard';
|
|
2
|
+
export { DEFAULT_DECOMPRESSION_LIMITS } from './decompression-guard';
|
|
3
|
+
export type { OpenZipOptions, ZipArchive } from './reader';
|
|
4
|
+
export { openZip } from './reader';
|
|
5
|
+
export type { StreamingEntryWriter, ZipWriter } from './writer';
|
|
6
|
+
export { createZipWriter } from './writer';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type DecompressionLimitsInput } from './decompression-guard';
|
|
2
|
+
import type { ZipArchive } from './reader';
|
|
3
|
+
/**
|
|
4
|
+
* Open a buffered xlsx archive in random-access mode. The archive bytes stay
|
|
5
|
+
* resident; entries inflate on demand inside `read(path)`.
|
|
6
|
+
*
|
|
7
|
+
* Falls back to `fflate.unzipSync` when the central directory uses ZIP64
|
|
8
|
+
* sentinel values (entry count == 0xFFFF or any size field == 0xFFFFFFFF) so
|
|
9
|
+
* external ZIP64 archives still load. xlsx files in the wild fit comfortably in
|
|
10
|
+
* ZIP32; the fallback exists for safety.
|
|
11
|
+
*
|
|
12
|
+
* `decompressionLimits` opts the archive into the zip-bomb safeguards
|
|
13
|
+
* documented on {@link DecompressionLimits}; pass `false` to disable. Defaults
|
|
14
|
+
* fit any legitimate xlsx.
|
|
15
|
+
*/
|
|
16
|
+
export declare function openRandomAccessArchive(bytes: Uint8Array, decompressionLimits?: DecompressionLimitsInput): ZipArchive;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { XlsxSource } from '../io/source';
|
|
2
|
+
import type { DecompressionLimits } from './decompression-guard';
|
|
3
|
+
export interface ZipArchive {
|
|
4
|
+
/** Sorted list of all entry paths in the archive. */
|
|
5
|
+
list(): string[];
|
|
6
|
+
/** Synchronous read; throws OpenXmlIoError when the path is unknown. */
|
|
7
|
+
read(path: string): Uint8Array;
|
|
8
|
+
/** Promise variant for symmetry with the future streaming reader. */
|
|
9
|
+
readAsync(path: string): Promise<Uint8Array>;
|
|
10
|
+
/**
|
|
11
|
+
* Streaming read: returns the entry's inflated bytes as a Web
|
|
12
|
+
* `ReadableStream<Uint8Array>` chunk-by-chunk. Lets callers (the streaming
|
|
13
|
+
* worksheet iterator, in particular) push the inflated payload through a SAX
|
|
14
|
+
* parser without first materialising it in full — peak memory for a sheet
|
|
15
|
+
* walk drops to the inflate window + SAX state instead of the entire
|
|
16
|
+
* uncompressed worksheet body. Throws OpenXmlIoError when the path is
|
|
17
|
+
* unknown.
|
|
18
|
+
*/
|
|
19
|
+
readStream(path: string): ReadableStream<Uint8Array>;
|
|
20
|
+
/** Whether the archive holds an entry at the given path. */
|
|
21
|
+
has(path: string): boolean;
|
|
22
|
+
/** Release the in-memory entry table. Subsequent reads throw. */
|
|
23
|
+
close(): void;
|
|
24
|
+
}
|
|
25
|
+
/** Options for {@link openZip}. */
|
|
26
|
+
export interface OpenZipOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Decompression-bomb safeguards applied while inflating archive entries. The
|
|
29
|
+
* default limits admit any legitimate xlsx and reject pathological archives
|
|
30
|
+
* (extreme compression ratios, gigabyte-scale entries). Pass `false` to
|
|
31
|
+
* disable the guard entirely — only safe when the source is fully trusted.
|
|
32
|
+
* See {@link DecompressionLimits} for the individual knobs.
|
|
33
|
+
*/
|
|
34
|
+
decompressionLimits?: DecompressionLimits | false;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Open a zip archive from any {@link XlsxSource}. The source is fully
|
|
38
|
+
* materialised in memory, the central directory is parsed once, and each
|
|
39
|
+
* entry is inflated on demand by {@link openRandomAccessArchive} — peak memory
|
|
40
|
+
* stays at compressed-archive size plus per-entry inflate scratch rather than
|
|
41
|
+
* holding every uncompressed entry resident. The fflate `unzipSync` fallback
|
|
42
|
+
* is preserved internally for ZIP64 / non-standard archives the random-access
|
|
43
|
+
* reader rejects.
|
|
44
|
+
*/
|
|
45
|
+
export declare function openZip(source: XlsxSource, opts?: OpenZipOptions): Promise<ZipArchive>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { XlsxSink } from '../io/sink';
|
|
2
|
+
export interface ZipWriter {
|
|
3
|
+
/**
|
|
4
|
+
* Stage an entry. Bytes are pushed through fflate's `ZipDeflate` /
|
|
5
|
+
* `ZipPassThrough` stream synchronously, so the deflated chunks land on the
|
|
6
|
+
* sink as the call runs (no per-entry buffering — see the streaming-behaviour
|
|
7
|
+
* test in `tests/phase-1/zip/writer.test.ts`). Streams (`ReadableStream`)
|
|
8
|
+
* are not accepted today; pass an already-materialised entry, or use
|
|
9
|
+
* {@link addStreamingEntry} for chunked writes.
|
|
10
|
+
*
|
|
11
|
+
* `compress` defaults to `true`. Pass `false` for already-compressed payloads
|
|
12
|
+
* (PNG/JPEG/zip-as-binary content like vbaProject.bin) so we don't pay
|
|
13
|
+
* deflate costs for no gain.
|
|
14
|
+
*/
|
|
15
|
+
addEntry(path: string, bytes: Uint8Array | ReadableStream<Uint8Array>, opts?: {
|
|
16
|
+
compress?: boolean;
|
|
17
|
+
}): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Open a streaming entry. Returns a writer the caller can `write()` chunks to
|
|
20
|
+
* and `end()` to seal the entry. Each chunk pushes through the same fflate
|
|
21
|
+
* `ZipDeflate` / `ZipPassThrough` machinery as `addEntry`, so peak memory
|
|
22
|
+
* stays at one chunk + deflate scratch even for multi-GB worksheets.
|
|
23
|
+
*
|
|
24
|
+
* Sequencing: only one streaming entry may be open at a time — `addEntry` and
|
|
25
|
+
* a second `addStreamingEntry` both throw until the current entry's `end()`
|
|
26
|
+
* resolves.
|
|
27
|
+
*/
|
|
28
|
+
addStreamingEntry(path: string, opts?: {
|
|
29
|
+
compress?: boolean;
|
|
30
|
+
}): StreamingEntryWriter;
|
|
31
|
+
/**
|
|
32
|
+
* Build the central directory and flush all bytes through the sink.
|
|
33
|
+
* Idempotent; subsequent calls resolve to the same payload.
|
|
34
|
+
*/
|
|
35
|
+
finalize(): Promise<Uint8Array>;
|
|
36
|
+
/**
|
|
37
|
+
* Release the sink and underlying writer without producing a valid archive.
|
|
38
|
+
* Use this from a surrounding catch block when serialization fails part-way
|
|
39
|
+
* through — without it, streaming sinks (`toFile` / `toWritable`) keep their
|
|
40
|
+
* file descriptors / writables open and the half-written xlsx looks valid on
|
|
41
|
+
* disk. Idempotent; safe to call after `finalize()`.
|
|
42
|
+
*/
|
|
43
|
+
abort(cause?: unknown): void;
|
|
44
|
+
}
|
|
45
|
+
/** Writer handle for a single streaming entry. */
|
|
46
|
+
export interface StreamingEntryWriter {
|
|
47
|
+
/** Push a chunk of bytes (already-encoded). Throws after `end()`. */
|
|
48
|
+
write(chunk: Uint8Array): void;
|
|
49
|
+
/** Seal the entry. Subsequent `write()` throws. Idempotent. */
|
|
50
|
+
end(): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* ZIP writer backed by fflate's streaming `Zip` class. Entries are pushed
|
|
54
|
+
* through `ZipDeflate` / `ZipPassThrough` streams as they arrive, so peak
|
|
55
|
+
* memory stays at the size of the in-flight entry plus the output buffer rather
|
|
56
|
+
* than the full archive.
|
|
57
|
+
*
|
|
58
|
+
* The sink contract is `toBytes()`, but that name is historical: the sink is
|
|
59
|
+
* driven by a chunked `write(chunk)` API that fans bytes out as they arrive.
|
|
60
|
+
* The buffered Node/browser sinks (`toBuffer`, `toBlob`, `toArrayBuffer`)
|
|
61
|
+
* concatenate the chunks for a single-shot result; streaming sinks
|
|
62
|
+
* (`toFile`, `toWritable`) forward each chunk to disk / the wrapped writable
|
|
63
|
+
* without ever holding the full archive resident. Either kind plugs in here.
|
|
64
|
+
*/
|
|
65
|
+
export declare function createZipWriter(sink: XlsxSink): ZipWriter;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splice ZIP64 EOCD record + locator into fflate's final chunk and
|
|
3
|
+
* patch the trailing EOCD entry-count fields with the 0xFFFF sentinel.
|
|
4
|
+
*
|
|
5
|
+
* `finalChunk` must be the [CD | EOCD] block fflate emits as its last
|
|
6
|
+
* ondata callback (everything before it is per-entry LFH/data/DD that
|
|
7
|
+
* we leave untouched). Returns a new chunk; the input is not mutated.
|
|
8
|
+
*
|
|
9
|
+
* Assumes per-entry sizes and central-directory offset fit in 32 bits;
|
|
10
|
+
* throws if not (xlsx archives never approach those limits).
|
|
11
|
+
*/
|
|
12
|
+
export declare function applyZip64EntryCountPatch(finalChunk: Uint8Array, totalEntries: number): Uint8Array;
|
package/dist/zip.mjs
ADDED