@shbernal/ts-xlsx 3.0.0 → 3.2.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 +34 -24
- package/dist/bytes.d.ts +10 -2
- package/dist/bytes.js +22 -0
- package/dist/core/address.d.ts +96 -2
- package/dist/core/address.js +87 -33
- package/dist/core/array-formula-ranges.d.ts +33 -0
- package/dist/core/array-formula-ranges.js +62 -0
- package/dist/core/autofilter.d.ts +4 -3
- package/dist/core/autofilter.js +31 -30
- package/dist/core/axis-handle.d.ts +2 -0
- package/dist/core/axis-handle.js +5 -2
- package/dist/core/cell.d.ts +4 -3
- package/dist/core/cell.js +4 -6
- package/dist/core/clone.d.ts +29 -0
- package/dist/core/clone.js +24 -0
- package/dist/core/color-resolution.js +4 -6
- package/dist/core/column.d.ts +1 -0
- package/dist/core/column.js +6 -2
- package/dist/core/comment-thread.d.ts +7 -3
- package/dist/core/comment-thread.js +2 -1
- package/dist/core/conditional-formatting-overlay.d.ts +11 -1
- package/dist/core/conditional-formatting-overlay.js +30 -3
- package/dist/core/conditional-formatting.d.ts +107 -11
- package/dist/core/conditional-formatting.js +76 -19
- package/dist/core/containers.d.ts +12 -0
- package/dist/core/containers.js +5 -0
- package/dist/core/data-validation-overlay.d.ts +7 -1
- package/dist/core/data-validation-overlay.js +19 -4
- package/dist/core/data-validation.d.ts +22 -0
- package/dist/core/data-validation.js +30 -4
- package/dist/core/date-format.d.ts +20 -0
- package/dist/core/date-format.js +170 -0
- package/dist/core/date.d.ts +43 -8
- package/dist/core/date.js +19 -3
- package/dist/core/formula-references.d.ts +26 -0
- package/dist/core/formula-references.js +173 -0
- package/dist/core/formula-scan.d.ts +2 -0
- package/dist/core/formula-scan.js +58 -0
- package/dist/core/formula.d.ts +76 -17
- package/dist/core/formula.js +87 -80
- package/dist/core/function-values.d.ts +4 -0
- package/dist/core/function-values.js +58 -0
- package/dist/core/future-functions.d.ts +3 -0
- package/dist/core/{modern-functions.js → future-functions.js} +119 -88
- package/dist/core/grid-edits.d.ts +30 -3
- package/dist/core/grid-edits.js +248 -81
- package/dist/core/grid-shift.d.ts +58 -9
- package/dist/core/grid-shift.js +26 -4
- package/dist/core/hyperlink.d.ts +39 -0
- package/dist/core/hyperlink.js +88 -0
- package/dist/core/image.d.ts +49 -14
- package/dist/core/image.js +16 -5
- package/dist/core/internal.d.ts +10 -2
- package/dist/core/limits.d.ts +25 -0
- package/dist/core/limits.js +4 -0
- package/dist/core/merge.d.ts +18 -4
- package/dist/core/merge.js +33 -20
- package/dist/core/page-setup.d.ts +26 -11
- package/dist/core/pivot-table.d.ts +49 -10
- package/dist/core/pivot-table.js +112 -60
- package/dist/core/protection.d.ts +66 -4
- package/dist/core/protection.js +6 -11
- package/dist/core/range.js +34 -30
- package/dist/core/row-input.js +2 -2
- package/dist/core/row.d.ts +1 -0
- package/dist/core/row.js +6 -2
- package/dist/core/structured-reference.d.ts +7 -0
- package/dist/core/structured-reference.js +7 -0
- package/dist/core/style.d.ts +85 -70
- package/dist/core/style.js +92 -28
- package/dist/core/table-style.d.ts +1 -1
- package/dist/core/table-style.js +4 -4
- package/dist/core/table.d.ts +64 -16
- package/dist/core/table.js +87 -40
- package/dist/core/theme.d.ts +2 -0
- package/dist/core/theme.js +9 -5
- package/dist/core/value.d.ts +60 -28
- package/dist/core/value.js +48 -43
- package/dist/core/workbook-media.d.ts +34 -0
- package/dist/core/workbook-media.js +44 -0
- package/dist/core/workbook-styles.d.ts +83 -1
- package/dist/core/workbook-styles.js +4 -0
- package/dist/core/workbook-theme.js +5 -3
- package/dist/core/workbook-vba.js +3 -2
- package/dist/core/workbook.d.ts +41 -3
- package/dist/core/workbook.js +46 -41
- package/dist/core/worksheet-comments.d.ts +2 -1
- package/dist/core/worksheet-comments.js +20 -13
- package/dist/core/worksheet-merges.d.ts +49 -0
- package/dist/core/worksheet-merges.js +65 -0
- package/dist/core/worksheet-model.d.ts +10 -2
- package/dist/core/worksheet-model.js +28 -9
- package/dist/core/worksheet-pictures.d.ts +3 -3
- package/dist/core/worksheet-pictures.js +7 -6
- package/dist/core/worksheet.d.ts +165 -27
- package/dist/core/worksheet.js +206 -89
- package/dist/customui/ribbon.js +2 -1
- package/dist/entries/core.d.ts +21 -14
- package/dist/entries/core.js +14 -7
- package/dist/entries/errors.d.ts +1 -0
- package/dist/entries/errors.js +1 -0
- package/dist/entries/xlsx.d.ts +1 -1
- package/dist/errors.d.ts +64 -0
- package/dist/errors.js +22 -0
- package/dist/hex.d.ts +8 -0
- package/dist/hex.js +3 -0
- package/dist/io/cell-metadata/metadata.d.ts +42 -0
- package/dist/io/cell-metadata/metadata.js +35 -0
- package/dist/io/cell-metadata/rich-values.d.ts +11 -0
- package/dist/io/cell-metadata/rich-values.js +80 -0
- package/dist/io/csv/delimiter.d.ts +21 -0
- package/dist/io/csv/delimiter.js +18 -0
- package/dist/io/csv/errors.d.ts +14 -0
- package/dist/io/csv/errors.js +5 -0
- package/dist/io/csv/read.d.ts +6 -1
- package/dist/io/csv/read.js +51 -22
- package/dist/io/csv/write.d.ts +19 -5
- package/dist/io/csv/write.js +24 -44
- package/dist/io/opc/inflate.js +14 -0
- package/dist/io/opc/namespaces.d.ts +16 -0
- package/dist/io/opc/namespaces.js +4 -0
- package/dist/io/opc/part-paths.d.ts +9 -0
- package/dist/io/opc/part-paths.js +5 -5
- package/dist/io/opc/read-opc.d.ts +58 -14
- package/dist/io/opc/read-opc.js +49 -21
- package/dist/io/opc/read-options.d.ts +5 -1
- package/dist/io/opc/sniff-format.d.ts +3 -3
- package/dist/io/opc/sniff-format.js +2 -2
- package/dist/io/opc/strict-relationships.d.ts +2 -0
- package/dist/io/opc/strict-relationships.js +12 -0
- package/dist/io/read-policy/column-budget.d.ts +26 -0
- package/dist/io/read-policy/column-budget.js +18 -0
- package/dist/io/read-policy/read-repair.d.ts +74 -0
- package/dist/io/read-policy/read-repair.js +119 -0
- package/dist/io/style/cell-style-resolution.d.ts +25 -0
- package/dist/io/style/cell-style-resolution.js +30 -0
- package/dist/io/style/xf-style.d.ts +23 -1
- package/dist/io/style/xf-style.js +8 -0
- package/dist/io/xlsb/formula.d.ts +2 -2
- package/dist/io/xlsb/formula.js +52 -35
- package/dist/io/xlsb/primitives.js +8 -14
- package/dist/io/xlsb/ptg-functions.d.ts +19 -10
- package/dist/io/xlsb/ptg-functions.js +495 -596
- package/dist/io/xlsb/read-metadata.d.ts +7 -0
- package/dist/io/xlsb/read-metadata.js +69 -0
- package/dist/io/xlsb/read-styles.js +45 -81
- package/dist/io/xlsb/read-worksheet.d.ts +26 -1
- package/dist/io/xlsb/read-worksheet.js +148 -106
- package/dist/io/xlsb/read.d.ts +6 -3
- package/dist/io/xlsb/read.js +70 -31
- package/dist/io/xlsb/record-stream.d.ts +30 -0
- package/dist/io/xlsb/record-stream.js +20 -0
- package/dist/io/xlsb/record-types.d.ts +14 -5
- package/dist/io/xlsb/record-types.js +14 -5
- package/dist/io/xlsb/sheet-protection.d.ts +20 -0
- package/dist/io/xlsb/sheet-protection.js +60 -0
- package/dist/io/xlsx/cell-accumulator.d.ts +24 -9
- package/dist/io/xlsx/cell-accumulator.js +74 -21
- package/dist/io/xlsx/cell-metadata.d.ts +39 -0
- package/dist/io/xlsx/cell-metadata.js +162 -0
- package/dist/io/xlsx/cell-value.d.ts +19 -5
- package/dist/io/xlsx/cell-value.js +45 -30
- package/dist/io/xlsx/color-xml.js +3 -2
- package/dist/io/xlsx/column-span.d.ts +11 -0
- package/dist/io/xlsx/column-span.js +9 -0
- package/dist/io/xlsx/comments.d.ts +9 -30
- package/dist/io/xlsx/comments.js +25 -83
- package/dist/io/xlsx/conditional-formatting.d.ts +43 -23
- package/dist/io/xlsx/conditional-formatting.js +437 -138
- package/dist/io/xlsx/data-validation.d.ts +12 -7
- package/dist/io/xlsx/data-validation.js +67 -53
- package/dist/io/xlsx/edit-vba.d.ts +7 -2
- package/dist/io/xlsx/edit-vba.js +52 -52
- package/dist/io/xlsx/font-xml.d.ts +7 -0
- package/dist/io/xlsx/font-xml.js +104 -0
- package/dist/io/xlsx/hyperlinks.d.ts +19 -21
- package/dist/io/xlsx/hyperlinks.js +12 -32
- package/dist/io/xlsx/images.d.ts +49 -16
- package/dist/io/xlsx/images.js +149 -50
- package/dist/io/xlsx/namespaces.d.ts +24 -0
- package/dist/io/xlsx/namespaces.js +11 -0
- package/dist/io/xlsx/package-plan.d.ts +60 -15
- package/dist/io/xlsx/package-plan.js +83 -18
- package/dist/io/xlsx/part-names.d.ts +6 -8
- package/dist/io/xlsx/part-names.js +3 -7
- package/dist/io/xlsx/pivot.d.ts +5 -5
- package/dist/io/xlsx/pivot.js +26 -24
- package/dist/io/xlsx/preserved-splices.d.ts +6 -0
- package/dist/io/xlsx/preserved-splices.js +74 -0
- package/dist/io/xlsx/read-comments.d.ts +29 -0
- package/dist/io/xlsx/read-comments.js +75 -0
- package/dist/io/xlsx/read-parts.d.ts +59 -0
- package/dist/io/xlsx/read-parts.js +259 -0
- package/dist/io/xlsx/read-pivot.js +11 -4
- package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +8 -5
- package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +24 -4
- package/dist/io/xlsx/read-rows.d.ts +35 -11
- package/dist/io/xlsx/read-rows.js +73 -49
- package/dist/io/xlsx/read-shared-strings.js +3 -2
- package/dist/io/xlsx/read-styles.d.ts +0 -30
- package/dist/io/xlsx/read-styles.js +45 -105
- package/dist/io/xlsx/read-workbook-xml.d.ts +42 -0
- package/dist/io/xlsx/read-workbook-xml.js +175 -0
- package/dist/io/xlsx/read-worksheet.d.ts +9 -3
- package/dist/io/xlsx/read-worksheet.js +70 -177
- package/dist/io/xlsx/read.d.ts +3 -14
- package/dist/io/xlsx/read.js +74 -411
- package/dist/io/xlsx/relationships.d.ts +3 -0
- package/dist/io/xlsx/relationships.js +4 -0
- package/dist/io/xlsx/rich-text.js +1 -1
- package/dist/io/xlsx/row-position.d.ts +20 -0
- package/dist/io/xlsx/row-position.js +11 -0
- package/dist/io/xlsx/row-xml.d.ts +139 -0
- package/dist/io/xlsx/row-xml.js +222 -0
- package/dist/io/xlsx/shared-formulas.js +2 -2
- package/dist/io/xlsx/sheet-properties.d.ts +10 -1
- package/dist/io/xlsx/sheet-properties.js +182 -20
- package/dist/io/xlsx/strict-parts.d.ts +7 -0
- package/dist/io/xlsx/strict-parts.js +171 -0
- package/dist/io/xlsx/style-elements.d.ts +41 -0
- package/dist/io/xlsx/style-elements.js +136 -0
- package/dist/io/xlsx/styles.d.ts +17 -3
- package/dist/io/xlsx/styles.js +13 -209
- package/dist/io/xlsx/tables.d.ts +10 -2
- package/dist/io/xlsx/tables.js +55 -52
- package/dist/io/xlsx/theme-xml.d.ts +32 -4
- package/dist/io/xlsx/theme-xml.js +106 -71
- package/dist/io/xlsx/threaded-comments.d.ts +14 -11
- package/dist/io/xlsx/threaded-comments.js +16 -8
- package/dist/io/xlsx/workbook-xml.d.ts +45 -6
- package/dist/io/xlsx/workbook-xml.js +62 -54
- package/dist/io/xlsx/worksheet-xml.d.ts +26 -70
- package/dist/io/xlsx/worksheet-xml.js +69 -282
- package/dist/io/xlsx/write-stream.d.ts +90 -19
- package/dist/io/xlsx/write-stream.js +80 -25
- package/dist/io/xlsx/write.d.ts +12 -6
- package/dist/io/xlsx/write.js +226 -123
- package/dist/rel-type.d.ts +25 -0
- package/dist/rel-type.js +9 -0
- package/dist/token-set.d.ts +13 -0
- package/dist/token-set.js +4 -1
- package/dist/vba/bytes.d.ts +16 -5
- package/dist/vba/bytes.js +27 -6
- package/dist/vba/cfb-format.d.ts +55 -0
- package/dist/vba/cfb-format.js +35 -0
- package/dist/vba/cfb-writer.d.ts +8 -0
- package/dist/vba/cfb-writer.js +40 -40
- package/dist/vba/cfb.d.ts +21 -4
- package/dist/vba/cfb.js +124 -90
- package/dist/vba/codepage.js +2 -1
- package/dist/vba/dir-records.d.ts +6 -0
- package/dist/vba/dir-records.js +10 -2
- package/dist/vba/errors.d.ts +11 -4
- package/dist/vba/index.d.ts +0 -2
- package/dist/vba/index.js +0 -2
- package/dist/vba/ms-ovba.d.ts +6 -2
- package/dist/vba/ms-ovba.js +66 -22
- package/dist/vba/project-editor.js +129 -119
- package/dist/vba/project.d.ts +15 -1
- package/dist/vba/project.js +38 -13
- package/dist/vba/vba-encoding.d.ts +4 -10
- package/dist/vba/vba-encoding.js +3 -17
- package/dist/xml/xml-attrs.d.ts +37 -0
- package/dist/xml/xml-attrs.js +30 -0
- package/dist/xml/xml-chars.d.ts +40 -0
- package/dist/xml/xml-chars.js +12 -0
- package/dist/xml/xml-namespaces.d.ts +31 -0
- package/dist/xml/xml-namespaces.js +50 -0
- package/dist/xml/xml-read.d.ts +101 -11
- package/dist/xml/xml-read.js +150 -18
- package/dist/xml/xml-scan.d.ts +25 -34
- package/dist/xml/xml-scan.js +69 -46
- package/dist/xml/xml.d.ts +59 -26
- package/dist/xml/xml.js +45 -23
- package/package.json +15 -9
- package/skills/ts-xlsx-upstream/SKILL.md +21 -13
- package/dist/core/modern-functions.d.ts +0 -1
|
@@ -1,31 +1,16 @@
|
|
|
1
|
-
import { tryDecodeRange } from '../../core/address.js';
|
|
2
|
-
import { isHyperlinkValue, isRichTextValue } from '../../core/value.js';
|
|
1
|
+
import { boundedRect, tryDecodeRange } from '../../core/address.js';
|
|
3
2
|
import {} from '../../xml/xml-read.js';
|
|
4
3
|
import { localName } from '../../xml/xml-scan.js';
|
|
5
4
|
import { escapeAttr, textAttr } from '../../xml/xml.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
for (const { cells } of sheet.rows()) {
|
|
9
|
-
for (const cell of cells) {
|
|
10
|
-
const value = cell.value;
|
|
11
|
-
if (isHyperlinkValue(value)) {
|
|
12
|
-
links.push({
|
|
13
|
-
ref: value.range ?? cell.address,
|
|
14
|
-
target: value.hyperlink,
|
|
15
|
-
...(value.tooltip !== undefined ? { tooltip: value.tooltip } : {}),
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return links;
|
|
21
|
-
}
|
|
5
|
+
import { relAttr } from '../opc/namespaces.js';
|
|
6
|
+
import { REL } from './relationships.js';
|
|
22
7
|
export function planHyperlinks(links, rels) {
|
|
23
8
|
return links.map((link) => {
|
|
24
9
|
const tooltip = link.tooltip !== undefined ? { tooltip: link.tooltip } : {};
|
|
25
10
|
if (link.target.startsWith('#')) {
|
|
26
11
|
return { ref: link.ref, location: link.target.slice(1), ...tooltip };
|
|
27
12
|
}
|
|
28
|
-
return { ref: link.ref, relId: rels.
|
|
13
|
+
return { ref: link.ref, relId: rels.addExternal(REL.hyperlink, link.target), ...tooltip };
|
|
29
14
|
});
|
|
30
15
|
}
|
|
31
16
|
export function hyperlinksXml(links) {
|
|
@@ -45,15 +30,16 @@ export function sheetHyperlinkPass() {
|
|
|
45
30
|
const links = [];
|
|
46
31
|
return {
|
|
47
32
|
handlers: {
|
|
48
|
-
onOpen(name, attrs) {
|
|
33
|
+
onOpen(name, attrs, _selfClosing, scope) {
|
|
49
34
|
if (localName(name) !== 'hyperlink')
|
|
50
35
|
return;
|
|
51
36
|
const ref = attrs.ref;
|
|
52
37
|
if (ref === undefined)
|
|
53
38
|
return;
|
|
39
|
+
const rid = relAttr(scope, attrs, 'id');
|
|
54
40
|
links.push({
|
|
55
41
|
ref,
|
|
56
|
-
...(
|
|
42
|
+
...(rid !== undefined ? { rid } : {}),
|
|
57
43
|
...(attrs.location !== undefined ? { location: attrs.location } : {}),
|
|
58
44
|
...(attrs.tooltip !== undefined ? { tooltip: attrs.tooltip } : {}),
|
|
59
45
|
});
|
|
@@ -68,19 +54,13 @@ export function applyHyperlinks(sheet, links, targetOf) {
|
|
|
68
54
|
if (target === undefined)
|
|
69
55
|
continue;
|
|
70
56
|
const decoded = tryDecodeRange(link.ref);
|
|
71
|
-
if (decoded === undefined || decoded
|
|
57
|
+
if (decoded === undefined || boundedRect(decoded) === undefined)
|
|
72
58
|
continue;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const spansRange = decoded.tl.address !== decoded.br.address;
|
|
77
|
-
const value = {
|
|
78
|
-
hyperlink: target,
|
|
79
|
-
text,
|
|
59
|
+
sheet.addHyperlink({
|
|
60
|
+
ref: link.ref,
|
|
61
|
+
target,
|
|
80
62
|
...(link.tooltip !== undefined ? { tooltip: link.tooltip } : {}),
|
|
81
|
-
|
|
82
|
-
};
|
|
83
|
-
cell.value = value;
|
|
63
|
+
});
|
|
84
64
|
}
|
|
85
65
|
}
|
|
86
66
|
function resolveTarget(link, targetOf) {
|
package/dist/io/xlsx/images.d.ts
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
|
-
import { type AnchorPoint, type Extent, type ImageAnchor, type ImageEditAs } from '../../core/image.ts';
|
|
1
|
+
import { type AnchorPoint, type Extent, type ImageAnchor, type ImageCrop, type ImageEditAs, type PictureProperties } from '../../core/image.ts';
|
|
2
2
|
/** The content type for a media part's `<Default Extension>` entry in `[Content_Types].xml`. */
|
|
3
3
|
export declare function imageContentType(extension: string): string;
|
|
4
|
-
/** One image placed in a drawing: where it sits
|
|
5
|
-
*
|
|
4
|
+
/** One image placed in a drawing: where it sits, the drawing-local relationship id that ties it to its
|
|
5
|
+
* media bytes, and the picture's own properties. */
|
|
6
6
|
export interface DrawingImage {
|
|
7
7
|
readonly anchor: ImageAnchor;
|
|
8
8
|
/** The `r:embed` id referencing this image's entry in the drawing's own `.rels`. */
|
|
9
9
|
readonly embedId: string;
|
|
10
|
+
readonly properties: PictureProperties;
|
|
11
|
+
/** The `r:id` of the hyperlink relationship in the drawing's own `.rels`, when the picture is a link. */
|
|
12
|
+
readonly hyperlinkId?: string;
|
|
10
13
|
}
|
|
11
14
|
/** The `xl/drawings/drawing{n}.xml` part: one anchor per image, two-cell or one-cell by its shape. */
|
|
12
15
|
export declare function drawingXml(images: readonly DrawingImage[]): string;
|
|
13
|
-
/**
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
+
/**
|
|
17
|
+
* A drawing kept from a file with pictures added to it: each picture's anchor goes after the drawing's
|
|
18
|
+
* own content, so it draws on top, as a picture inserted last does in Excel.
|
|
19
|
+
*
|
|
20
|
+
* A drawing numbers its shapes by `cNvPr id`, unique within it, so the pictures take ids past the
|
|
21
|
+
* highest one there. Their `r:embed` and link ids are the caller's, allocated past the relationships
|
|
22
|
+
* the drawing already holds.
|
|
23
|
+
*
|
|
24
|
+
* @throws {AuthoringError} if the kept part has no `<wsDr>` root to add a picture to.
|
|
25
|
+
*/
|
|
26
|
+
export declare function mergePictures(drawing: string, images: readonly DrawingImage[]): string;
|
|
16
27
|
/** An image anchor parsed from a drawing part, with the `r:embed` id that names its media. A two-cell
|
|
17
|
-
* anchor carries `to`
|
|
28
|
+
* anchor carries `to` and its `editAs`, the schema default filled in; a one-cell anchor carries `ext`
|
|
29
|
+
* instead. */
|
|
18
30
|
export interface ParsedImageAnchor {
|
|
19
31
|
readonly from: AnchorPoint;
|
|
20
32
|
readonly to?: AnchorPoint;
|
|
@@ -22,13 +34,34 @@ export interface ParsedImageAnchor {
|
|
|
22
34
|
readonly editAs?: ImageEditAs;
|
|
23
35
|
readonly rotation?: number;
|
|
24
36
|
readonly embed: string;
|
|
37
|
+
readonly description?: string;
|
|
38
|
+
readonly title?: string;
|
|
39
|
+
readonly crop?: ImageCrop;
|
|
40
|
+
/** The `r:id` of the picture's `a:hlinkClick`, for the caller to resolve against the drawing's rels. */
|
|
41
|
+
readonly hyperlinkId?: string;
|
|
42
|
+
readonly tooltip?: string;
|
|
25
43
|
}
|
|
26
|
-
/**
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
44
|
+
/** A drawing part as the reader sees it: the picture anchors it could model, and whether those anchors
|
|
45
|
+
* are the whole of it. */
|
|
46
|
+
export interface ParsedDrawing {
|
|
47
|
+
readonly anchors: readonly ParsedImageAnchor[];
|
|
48
|
+
/**
|
|
49
|
+
* Whether every anchor is a two-cell or one-cell anchor holding exactly one embedded picture. When it
|
|
50
|
+
* is not, writing the drawing back from `anchors` would leave the rest out, so the reader keeps the
|
|
51
|
+
* whole part byte for byte instead.
|
|
52
|
+
*/
|
|
53
|
+
readonly fullyModeled: boolean;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Parse a drawing part into its picture anchors (`<xdr:twoCellAnchor>` and `<xdr:oneCellAnchor>`), and
|
|
57
|
+
* decide in the same scan whether they are the whole drawing. It is fully modeled only when every
|
|
58
|
+
* anchor holds exactly one picture whose bytes are embedded; anything else in it, including a picture
|
|
59
|
+
* that links its image rather than embedding it, has no place in the image model.
|
|
60
|
+
*
|
|
61
|
+
* This used to be two scans: one listing the content the model skips, and this one. The list missed
|
|
62
|
+
* an absolute anchor and a linked picture, so a drawing holding either counted as modeled and lost them
|
|
63
|
+
* on write. What an anchor holds is now judged by what the parse found in it, one embedded picture or
|
|
64
|
+
* not, so no kind of anchor content can slip past unnamed; the list left names only the anchor kinds
|
|
65
|
+
* and wrappers this parse does not otherwise open an anchor for.
|
|
66
|
+
*/
|
|
67
|
+
export declare function parseDrawing(xml: string): ParsedDrawing;
|
package/dist/io/xlsx/images.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { isImageEditAs, isOneCellAnchor, } from '../../core/image.js';
|
|
2
|
-
import {
|
|
3
|
-
import { enumToken,
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { assertWritableNumber, AuthoringError } from '../../errors.js';
|
|
3
|
+
import { enumToken, numFinite, numInteger } from '../../xml/xml-attrs.js';
|
|
4
|
+
import { elementRange, openElements, parseXml, TextCapture } from '../../xml/xml-read.js';
|
|
5
|
+
import { localName } from '../../xml/xml-scan.js';
|
|
6
|
+
import { checkedToken, escapeAttr, intAttr, numAttr, numberText, textAttr, XML_DECLARATION, } from '../../xml/xml.js';
|
|
7
|
+
import { relAttr, RELATIONSHIPS_NS } from '../opc/namespaces.js';
|
|
7
8
|
import { DRAWINGML_NS, XDR_NS } from './namespaces.js';
|
|
8
|
-
const IMAGE_REL_TYPE = `${RELATIONSHIPS_NS}/image`;
|
|
9
9
|
const IMAGE_CONTENT_TYPES = new Map([
|
|
10
10
|
['png', 'image/png'],
|
|
11
11
|
['jpg', 'image/jpeg'],
|
|
@@ -22,81 +22,185 @@ export function imageContentType(extension) {
|
|
|
22
22
|
const ext = extension.toLowerCase();
|
|
23
23
|
return IMAGE_CONTENT_TYPES.get(ext) ?? `image/${ext}`;
|
|
24
24
|
}
|
|
25
|
+
const ANCHOR_NAMESPACES = ` xmlns:xdr="${XDR_NS}" xmlns:a="${DRAWINGML_NS}" xmlns:r="${RELATIONSHIPS_NS}"`;
|
|
25
26
|
export function drawingXml(images) {
|
|
26
|
-
const anchors = images.map((image, i) => anchorXml(image, i + 1)).join('');
|
|
27
|
-
return
|
|
28
|
-
`<xdr:wsDr xmlns:xdr="${XDR_NS}" xmlns:a="${DRAWINGML_NS}" xmlns:r="${RELATIONSHIPS_NS}">` +
|
|
29
|
-
anchors +
|
|
30
|
-
'</xdr:wsDr>');
|
|
27
|
+
const anchors = images.map((image, i) => anchorXml(image, i + 1, '')).join('');
|
|
28
|
+
return `${XML_DECLARATION}<xdr:wsDr${ANCHOR_NAMESPACES}>${anchors}</xdr:wsDr>`;
|
|
31
29
|
}
|
|
32
|
-
function
|
|
30
|
+
export function mergePictures(drawing, images) {
|
|
31
|
+
const root = elementRange(drawing, ['wsDr']);
|
|
32
|
+
if (root === undefined) {
|
|
33
|
+
throw new AuthoringError('cannot add a picture to a kept drawing that has no <wsDr> root');
|
|
34
|
+
}
|
|
35
|
+
let lastId = 0;
|
|
36
|
+
for (const { attrs } of openElements(drawing, 'cNvPr')) {
|
|
37
|
+
lastId = Math.max(lastId, numInteger(attrs.id, 0) ?? 0);
|
|
38
|
+
}
|
|
39
|
+
const anchors = images
|
|
40
|
+
.map((image, i) => anchorXml(image, lastId + i + 1, ANCHOR_NAMESPACES))
|
|
41
|
+
.join('');
|
|
42
|
+
if (root.contentStart === root.end) {
|
|
43
|
+
const open = drawing.slice(root.start, root.end).replace(/\s*\/>$/, '>');
|
|
44
|
+
return `${drawing.slice(0, root.start)}${open}${anchors}</${root.name}>${drawing.slice(root.end)}`;
|
|
45
|
+
}
|
|
46
|
+
return drawing.slice(0, root.contentEnd) + anchors + drawing.slice(root.contentEnd);
|
|
47
|
+
}
|
|
48
|
+
function anchorXml(image, id, namespaces) {
|
|
33
49
|
const { anchor } = image;
|
|
50
|
+
const pic = picXml(image, id, anchor.rotation);
|
|
34
51
|
return isOneCellAnchor(anchor)
|
|
35
|
-
? oneCellAnchorXml(anchor.from, anchor.ext,
|
|
36
|
-
: twoCellAnchorXml(anchor.from, anchor.to, anchor.editAs ?? 'oneCell',
|
|
52
|
+
? oneCellAnchorXml(anchor.from, anchor.ext, pic, namespaces)
|
|
53
|
+
: twoCellAnchorXml(anchor.from, anchor.to, anchor.editAs ?? 'oneCell', pic, namespaces);
|
|
37
54
|
}
|
|
38
|
-
function twoCellAnchorXml(from, to, editAs,
|
|
39
|
-
return (`<xdr:twoCellAnchor editAs="${checkedToken(editAs, isImageEditAs, 'image anchor edit mode')}">` +
|
|
55
|
+
function twoCellAnchorXml(from, to, editAs, pic, namespaces) {
|
|
56
|
+
return (`<xdr:twoCellAnchor${namespaces} editAs="${checkedToken(editAs, isImageEditAs, 'image anchor edit mode')}">` +
|
|
40
57
|
`<xdr:from>${anchorPointXml(from)}</xdr:from>` +
|
|
41
58
|
`<xdr:to>${anchorPointXml(to)}</xdr:to>` +
|
|
42
|
-
|
|
59
|
+
pic +
|
|
43
60
|
'<xdr:clientData/>' +
|
|
44
61
|
'</xdr:twoCellAnchor>');
|
|
45
62
|
}
|
|
46
|
-
function oneCellAnchorXml(from, ext,
|
|
47
|
-
return (
|
|
63
|
+
function oneCellAnchorXml(from, ext, pic, namespaces) {
|
|
64
|
+
return (`<xdr:oneCellAnchor${namespaces}>` +
|
|
48
65
|
`<xdr:from>${anchorPointXml(from)}</xdr:from>` +
|
|
49
66
|
`<xdr:ext${numAttr('cx', ext.cx)}${numAttr('cy', ext.cy)}/>` +
|
|
50
|
-
|
|
67
|
+
pic +
|
|
51
68
|
'<xdr:clientData/>' +
|
|
52
69
|
'</xdr:oneCellAnchor>');
|
|
53
70
|
}
|
|
54
|
-
function picXml(
|
|
71
|
+
function picXml(image, id, rotation) {
|
|
72
|
+
const { embedId, properties, hyperlinkId } = image;
|
|
55
73
|
const xfrm = rotation !== undefined ? `<a:xfrm${numAttr('rot', rotation)}/>` : '';
|
|
74
|
+
const attributes = textAttr('descr', properties.description) + textAttr('title', properties.title);
|
|
75
|
+
const link = hyperlinkId === undefined
|
|
76
|
+
? ''
|
|
77
|
+
: `<a:hlinkClick r:id="${escapeAttr(hyperlinkId)}"` +
|
|
78
|
+
`${textAttr('tooltip', properties.hyperlink?.tooltip)}/>`;
|
|
79
|
+
const cNvPr = link === ''
|
|
80
|
+
? `<xdr:cNvPr id="${id}" name="Picture ${id}"${attributes}/>`
|
|
81
|
+
: `<xdr:cNvPr id="${id}" name="Picture ${id}"${attributes}>${link}</xdr:cNvPr>`;
|
|
56
82
|
return ('<xdr:pic>' +
|
|
57
|
-
`<xdr:nvPicPr
|
|
83
|
+
`<xdr:nvPicPr>${cNvPr}` +
|
|
58
84
|
'<xdr:cNvPicPr><a:picLocks noChangeAspect="1"/></xdr:cNvPicPr></xdr:nvPicPr>' +
|
|
59
85
|
`<xdr:blipFill><a:blip r:embed="${embedId}"/>` +
|
|
86
|
+
srcRectXml(properties.crop) +
|
|
60
87
|
'<a:stretch><a:fillRect/></a:stretch></xdr:blipFill>' +
|
|
61
88
|
`<xdr:spPr>${xfrm}<a:prstGeom prst="rect"><a:avLst/></a:prstGeom></xdr:spPr>` +
|
|
62
89
|
'</xdr:pic>');
|
|
63
90
|
}
|
|
91
|
+
const CROP_UNITS = 100_000;
|
|
92
|
+
const INT_MAX = 2_147_483_647;
|
|
93
|
+
function srcRectXml(crop) {
|
|
94
|
+
if (crop === undefined)
|
|
95
|
+
return '';
|
|
96
|
+
const edge = (name, fraction) => {
|
|
97
|
+
if (fraction === undefined)
|
|
98
|
+
return '';
|
|
99
|
+
assertWritableNumber(fraction);
|
|
100
|
+
const units = Math.round(fraction * CROP_UNITS);
|
|
101
|
+
if (units > INT_MAX) {
|
|
102
|
+
throw new AuthoringError(`cannot write the picture crop ${name}="${units}": past xsd:int`);
|
|
103
|
+
}
|
|
104
|
+
return units === 0 ? '' : intAttr(name, units, -INT_MAX - 1);
|
|
105
|
+
};
|
|
106
|
+
const attributes = edge('l', crop.left) + edge('t', crop.top) + edge('r', crop.right) + edge('b', crop.bottom);
|
|
107
|
+
return attributes === '' ? '' : `<a:srcRect${attributes}/>`;
|
|
108
|
+
}
|
|
109
|
+
function cropEdge(value) {
|
|
110
|
+
if (value === undefined)
|
|
111
|
+
return undefined;
|
|
112
|
+
const percent = value.endsWith('%') ? numFinite(value.slice(0, -1)) : undefined;
|
|
113
|
+
const units = percent === undefined ? numInteger(value) : Math.round(percent * 1000);
|
|
114
|
+
if (units === undefined || units === 0 || units > INT_MAX || units < -INT_MAX - 1) {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
return units / CROP_UNITS;
|
|
118
|
+
}
|
|
64
119
|
function anchorPointXml(point) {
|
|
65
120
|
return (`<xdr:col>${numberText(point.col)}</xdr:col>` +
|
|
66
121
|
`<xdr:colOff>${numberText(point.colOff ?? 0)}</xdr:colOff>` +
|
|
67
122
|
`<xdr:row>${numberText(point.row)}</xdr:row>` +
|
|
68
123
|
`<xdr:rowOff>${numberText(point.rowOff ?? 0)}</xdr:rowOff>`);
|
|
69
124
|
}
|
|
70
|
-
export function drawingRelsXml(mediaTargets) {
|
|
71
|
-
return relationshipsPart(mediaTargets.map((target, i) => relationship(`rId${i + 1}`, IMAGE_REL_TYPE, target)));
|
|
72
|
-
}
|
|
73
125
|
function blankPoint() {
|
|
74
126
|
return { col: 0, row: 0, colOff: 0, rowOff: 0 };
|
|
75
127
|
}
|
|
128
|
+
const UNMODELED_CONTENT = new Set([
|
|
129
|
+
'graphicFrame',
|
|
130
|
+
'sp',
|
|
131
|
+
'cxnSp',
|
|
132
|
+
'grpSp',
|
|
133
|
+
'contentPart',
|
|
134
|
+
'absoluteAnchor',
|
|
135
|
+
'AlternateContent',
|
|
136
|
+
]);
|
|
76
137
|
export function parseDrawing(xml) {
|
|
77
138
|
const anchors = [];
|
|
139
|
+
let fullyModeled = true;
|
|
78
140
|
let from = null;
|
|
79
141
|
let to = null;
|
|
80
142
|
let ext;
|
|
81
143
|
let editAs;
|
|
82
144
|
let rotation;
|
|
83
145
|
let embed;
|
|
146
|
+
let pictures = 0;
|
|
147
|
+
let properties = {};
|
|
84
148
|
let target = null;
|
|
85
149
|
let picDepth = 0;
|
|
86
150
|
const coord = new TextCapture(COORDINATES);
|
|
87
151
|
parseXml(xml, {
|
|
88
|
-
onOpen(name, attrs, selfClosing) {
|
|
152
|
+
onOpen(name, attrs, selfClosing, scope) {
|
|
89
153
|
const local = localName(name);
|
|
90
|
-
if (local
|
|
154
|
+
if (UNMODELED_CONTENT.has(local)) {
|
|
155
|
+
fullyModeled = false;
|
|
156
|
+
}
|
|
157
|
+
else if (local === 'twoCellAnchor' || local === 'oneCellAnchor') {
|
|
91
158
|
from = blankPoint();
|
|
92
159
|
to = local === 'twoCellAnchor' ? blankPoint() : null;
|
|
93
160
|
ext = undefined;
|
|
94
161
|
rotation = undefined;
|
|
95
162
|
embed = undefined;
|
|
96
|
-
|
|
163
|
+
pictures = 0;
|
|
164
|
+
properties = {};
|
|
165
|
+
editAs =
|
|
166
|
+
local === 'twoCellAnchor'
|
|
167
|
+
? (enumToken(attrs.editAs, isImageEditAs) ?? 'twoCell')
|
|
168
|
+
: undefined;
|
|
97
169
|
}
|
|
98
170
|
else if (local === 'pic') {
|
|
99
171
|
picDepth++;
|
|
172
|
+
pictures++;
|
|
173
|
+
}
|
|
174
|
+
else if (local === 'cNvPr' && picDepth > 0) {
|
|
175
|
+
if (attrs.descr !== undefined && attrs.descr !== '')
|
|
176
|
+
properties.description = attrs.descr;
|
|
177
|
+
if (attrs.title !== undefined && attrs.title !== '')
|
|
178
|
+
properties.title = attrs.title;
|
|
179
|
+
}
|
|
180
|
+
else if (local === 'hlinkClick' && picDepth > 0) {
|
|
181
|
+
const id = relAttr(scope, attrs, 'id');
|
|
182
|
+
if (id !== undefined && id !== '') {
|
|
183
|
+
properties.hyperlinkId = id;
|
|
184
|
+
if (attrs.tooltip !== undefined)
|
|
185
|
+
properties.tooltip = attrs.tooltip;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
else if (local === 'srcRect' && picDepth > 0) {
|
|
189
|
+
const crop = {};
|
|
190
|
+
const left = cropEdge(attrs.l);
|
|
191
|
+
const top = cropEdge(attrs.t);
|
|
192
|
+
const right = cropEdge(attrs.r);
|
|
193
|
+
const bottom = cropEdge(attrs.b);
|
|
194
|
+
if (left !== undefined)
|
|
195
|
+
crop.left = left;
|
|
196
|
+
if (top !== undefined)
|
|
197
|
+
crop.top = top;
|
|
198
|
+
if (right !== undefined)
|
|
199
|
+
crop.right = right;
|
|
200
|
+
if (bottom !== undefined)
|
|
201
|
+
crop.bottom = bottom;
|
|
202
|
+
if (Object.keys(crop).length > 0)
|
|
203
|
+
properties.crop = crop;
|
|
100
204
|
}
|
|
101
205
|
else if (local === 'xfrm' && picDepth > 0) {
|
|
102
206
|
const rot = numFinite(attrs.rot);
|
|
@@ -116,9 +220,11 @@ export function parseDrawing(xml) {
|
|
|
116
220
|
ext = { cx, cy };
|
|
117
221
|
}
|
|
118
222
|
else if (local === 'blip') {
|
|
119
|
-
const value = attrs
|
|
223
|
+
const value = relAttr(scope, attrs, 'embed');
|
|
120
224
|
if (value !== undefined)
|
|
121
225
|
embed = value;
|
|
226
|
+
if (relAttr(scope, attrs, 'link') !== undefined)
|
|
227
|
+
fullyModeled = false;
|
|
122
228
|
}
|
|
123
229
|
else if (target !== null) {
|
|
124
230
|
coord.open(local, selfClosing);
|
|
@@ -142,15 +248,19 @@ export function parseDrawing(xml) {
|
|
|
142
248
|
picDepth--;
|
|
143
249
|
}
|
|
144
250
|
else if (local === 'twoCellAnchor' || local === 'oneCellAnchor') {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
251
|
+
const rot = rotation !== undefined ? { rotation } : {};
|
|
252
|
+
if (from === null || embed === undefined || pictures !== 1) {
|
|
253
|
+
fullyModeled = false;
|
|
254
|
+
}
|
|
255
|
+
else if (to !== null) {
|
|
256
|
+
const mode = editAs !== undefined ? { editAs } : {};
|
|
257
|
+
anchors.push({ from: { ...from }, to: { ...to }, ...mode, ...rot, embed, ...properties });
|
|
258
|
+
}
|
|
259
|
+
else if (ext !== undefined) {
|
|
260
|
+
anchors.push({ from: { ...from }, ext, ...rot, embed, ...properties });
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
fullyModeled = false;
|
|
154
264
|
}
|
|
155
265
|
from = null;
|
|
156
266
|
to = null;
|
|
@@ -158,18 +268,7 @@ export function parseDrawing(xml) {
|
|
|
158
268
|
}
|
|
159
269
|
},
|
|
160
270
|
});
|
|
161
|
-
return anchors;
|
|
162
|
-
}
|
|
163
|
-
const UNMODELED_DRAWING_CONTENT = new Set(['graphicFrame', 'sp', 'cxnSp', 'grpSp']);
|
|
164
|
-
export function drawingHasUnmodeledContent(xml) {
|
|
165
|
-
let found = false;
|
|
166
|
-
parseXml(xml, {
|
|
167
|
-
onOpen(name) {
|
|
168
|
-
if (!found && UNMODELED_DRAWING_CONTENT.has(localName(name)))
|
|
169
|
-
found = true;
|
|
170
|
-
},
|
|
171
|
-
});
|
|
172
|
-
return found;
|
|
271
|
+
return { anchors, fullyModeled };
|
|
173
272
|
}
|
|
174
273
|
const COORDINATES = new Set(['col', 'colOff', 'row', 'rowOff']);
|
|
175
274
|
function setCoordinate(point, coord, value) {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* The package-level URIs (`.rels`, content types, the relationship vocabulary) describe the
|
|
10
10
|
* container rather than the spreadsheet inside it, and live in `../opc/namespaces.ts`.
|
|
11
11
|
*/
|
|
12
|
+
import type { NamespaceScope } from '../../xml/xml-namespaces.ts';
|
|
12
13
|
/**
|
|
13
14
|
* SpreadsheetML main namespace: the default `xmlns` of the workbook,
|
|
14
15
|
* worksheet, styles, sharedStrings, comments, table and pivot parts.
|
|
@@ -53,3 +54,26 @@ export declare const DATABAR_LINK_EXT_URI = "{B025F937-C7B1-47D3-B67F-A62EFF666E
|
|
|
53
54
|
export declare const DATA_VALIDATION_EXT_URI = "{CCE6A557-97BC-4b89-ADB6-D9C93CAAB3DF}";
|
|
54
55
|
export declare const SLICER_LIST_EXT_URI = "{A8765BA9-456A-4dab-B4F3-ACF838C121DE}";
|
|
55
56
|
export declare const SLICER_CACHES_EXT_URI = "{BBE1A952-AA13-448e-AADC-164F8A28A991}";
|
|
57
|
+
/** The extension a dynamic-array formula's cell-metadata block carries its properties in. */
|
|
58
|
+
export declare const DYNAMIC_ARRAY_PROPERTIES_EXT_URI = "{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}";
|
|
59
|
+
/** The 2017 dynamic-array namespace (`xda:`), which scopes those properties in `xl/metadata.xml`. */
|
|
60
|
+
export declare const DYNAMIC_ARRAY_NS = "http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray";
|
|
61
|
+
/** The extension a rich-value metadata block names its rich value in (`<xlrd:rvb i>`). */
|
|
62
|
+
export declare const RICH_VALUE_BLOCK_EXT_URI = "{3e2802c4-a4d2-4d8b-9148-e3be6c30e623}";
|
|
63
|
+
/** The 2017 rich-data namespace (`xlrd:`): the rich values, their structures, and the blocks naming them. */
|
|
64
|
+
export declare const RICH_DATA_NS = "http://schemas.microsoft.com/office/spreadsheetml/2017/richdata";
|
|
65
|
+
/**
|
|
66
|
+
* Whether an element belongs to the standard SpreadsheetML vocabulary rather than to an extension.
|
|
67
|
+
*
|
|
68
|
+
* This used to be spelled `!name.includes(':')`, on the assumption that only extension elements carry
|
|
69
|
+
* a prefix. A worksheet may bind the *main* namespace to a prefix instead, which is legal and which
|
|
70
|
+
* real toolchains emit, and then every element has a colon in it: such a file had every one of its
|
|
71
|
+
* data validations and conditional formats read as an unknown extension and dropped, silently.
|
|
72
|
+
*
|
|
73
|
+
* An unprefixed element counts even when the part declares no default namespace. A part with no
|
|
74
|
+
* `xmlns` at all is not conforming OOXML, but this scanner does not reject it, such parts were read
|
|
75
|
+
* before, and a fix that gains files by resolving namespaces should not lose files that have none.
|
|
76
|
+
*/
|
|
77
|
+
export declare function isMainNamespaceElement(scope: NamespaceScope, name: string): boolean;
|
|
78
|
+
/** The complement of {@link isMainNamespaceElement}: an element of one of the extension vocabularies. */
|
|
79
|
+
export declare function isExtensionElement(scope: NamespaceScope, name: string): boolean;
|
|
@@ -11,3 +11,14 @@ export const DATABAR_LINK_EXT_URI = '{B025F937-C7B1-47D3-B67F-A62EFF666E3E}';
|
|
|
11
11
|
export const DATA_VALIDATION_EXT_URI = '{CCE6A557-97BC-4b89-ADB6-D9C93CAAB3DF}';
|
|
12
12
|
export const SLICER_LIST_EXT_URI = '{A8765BA9-456A-4dab-B4F3-ACF838C121DE}';
|
|
13
13
|
export const SLICER_CACHES_EXT_URI = '{BBE1A952-AA13-448e-AADC-164F8A28A991}';
|
|
14
|
+
export const DYNAMIC_ARRAY_PROPERTIES_EXT_URI = '{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}';
|
|
15
|
+
export const DYNAMIC_ARRAY_NS = 'http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray';
|
|
16
|
+
export const RICH_VALUE_BLOCK_EXT_URI = '{3e2802c4-a4d2-4d8b-9148-e3be6c30e623}';
|
|
17
|
+
export const RICH_DATA_NS = 'http://schemas.microsoft.com/office/spreadsheetml/2017/richdata';
|
|
18
|
+
export function isMainNamespaceElement(scope, name) {
|
|
19
|
+
const namespace = scope.elementNamespace(name);
|
|
20
|
+
return namespace === SPREADSHEETML_NS || (namespace === undefined && !name.includes(':'));
|
|
21
|
+
}
|
|
22
|
+
export function isExtensionElement(scope, name) {
|
|
23
|
+
return !isMainNamespaceElement(scope, name);
|
|
24
|
+
}
|
|
@@ -5,29 +5,60 @@ import type { Table } from '../../core/table.ts';
|
|
|
5
5
|
import type { Workbook } from '../../core/workbook.ts';
|
|
6
6
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
7
7
|
import type { CommentCell } from './comments.ts';
|
|
8
|
-
import type {
|
|
9
|
-
|
|
8
|
+
import type { HyperlinkPlan } from './hyperlinks.ts';
|
|
9
|
+
import { type DrawingImage } from './images.ts';
|
|
10
|
+
/** One relationship a generated `.rels` part declares, its target already relative to the owner. */
|
|
11
|
+
export interface PlannedRelationship {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly type: string;
|
|
14
|
+
readonly target: string;
|
|
15
|
+
readonly external?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The relationships one part owns, recorded as their ids are handed out.
|
|
19
|
+
*
|
|
20
|
+
* An id and the relationship it names are one fact, so they are written down in one call. When the
|
|
21
|
+
* ids came from a counter and the `.rels` part was listed somewhere else, a sheet's set was spelled
|
|
22
|
+
* three times: once where ids were drawn, once in the rels renderer in another order, and once more in
|
|
23
|
+
* a nine-way condition deciding whether the rels part existed at all. A tenth kind of part needed all
|
|
24
|
+
* three edits, and missing the last dropped the `.rels` part while the sheet XML still cited the id.
|
|
25
|
+
* Now the ledger is the rels part, and a part with an empty ledger has none.
|
|
26
|
+
*
|
|
27
|
+
* Ids run `rId1`, `rId2`, … in the order parts are added, so no id is derived by summing the ones
|
|
28
|
+
* before it, and the `.rels` part lists them in that same order. One ledger per owning part; ids are
|
|
29
|
+
* scoped to it. A ledger adding to a part kept from a file skips the ids that part already holds.
|
|
30
|
+
*/
|
|
31
|
+
export declare class RelationshipLedger {
|
|
10
32
|
#private;
|
|
11
|
-
/**
|
|
12
|
-
|
|
33
|
+
/**
|
|
34
|
+
* @param owner the package path of the part whose `.rels` this is, `''` for the package root.
|
|
35
|
+
* @param taken the ids the part's `.rels` already holds, none of which a new relationship may take.
|
|
36
|
+
*/
|
|
37
|
+
constructor(owner: string, taken?: ReadonlySet<string>);
|
|
38
|
+
/** Record a relationship to a package part, named by its package path, and return its id. */
|
|
39
|
+
add(type: string, partPath: string): string;
|
|
40
|
+
/** Record a relationship to a target outside the package (a hyperlink's URL) and return its id. */
|
|
41
|
+
addExternal(type: string, url: string): string;
|
|
42
|
+
/** Record a relationship to a place inside this document (a picture link's `#Sheet1!C3`), kept as
|
|
43
|
+
* written rather than resolved as a part path, and return its id. */
|
|
44
|
+
addInDocument(type: string, location: string): string;
|
|
45
|
+
/** Every relationship recorded, in id order. */
|
|
46
|
+
get relationships(): readonly PlannedRelationship[];
|
|
13
47
|
}
|
|
14
48
|
export interface PivotPlan {
|
|
15
49
|
readonly number: number;
|
|
16
50
|
readonly cacheId: string;
|
|
17
51
|
readonly table: PivotTable;
|
|
18
|
-
readonly sheetRelId: string;
|
|
19
52
|
workbookRelId: string;
|
|
20
53
|
}
|
|
21
54
|
export interface CommentPlan {
|
|
22
55
|
readonly number: number;
|
|
23
56
|
readonly comments: readonly CommentCell[];
|
|
24
57
|
readonly vmlRelId: string;
|
|
25
|
-
readonly commentsRelId: string;
|
|
26
58
|
}
|
|
27
59
|
export interface ThreadedCommentPlan {
|
|
28
60
|
readonly number: number;
|
|
29
61
|
readonly threads: readonly CommentThread[];
|
|
30
|
-
readonly relId: string;
|
|
31
62
|
}
|
|
32
63
|
export interface PrinterSettingsPlan {
|
|
33
64
|
readonly number: number;
|
|
@@ -41,8 +72,6 @@ export interface TablePlan {
|
|
|
41
72
|
}
|
|
42
73
|
export interface BackgroundPlan {
|
|
43
74
|
readonly relId: string;
|
|
44
|
-
readonly mediaNumber: number;
|
|
45
|
-
readonly extension: string;
|
|
46
75
|
}
|
|
47
76
|
export interface PreservedPartPlan {
|
|
48
77
|
readonly path: string;
|
|
@@ -84,11 +113,8 @@ export interface PreservedPlan {
|
|
|
84
113
|
export interface DrawingPlan {
|
|
85
114
|
readonly number: number;
|
|
86
115
|
readonly relId: string;
|
|
87
|
-
readonly images: readonly
|
|
88
|
-
|
|
89
|
-
export interface ImagePlan extends DrawingImage {
|
|
90
|
-
readonly mediaNumber: number;
|
|
91
|
-
readonly extension: string;
|
|
116
|
+
readonly images: readonly DrawingImage[];
|
|
117
|
+
readonly relationships: readonly PlannedRelationship[];
|
|
92
118
|
}
|
|
93
119
|
export interface MediaPart {
|
|
94
120
|
readonly number: number;
|
|
@@ -108,4 +134,23 @@ export interface MediaPlan {
|
|
|
108
134
|
resolve(id: number): ResolvedMedia;
|
|
109
135
|
}
|
|
110
136
|
export declare function planMedia(workbook: Workbook, sheets: readonly Worksheet[]): MediaPlan;
|
|
111
|
-
|
|
137
|
+
/**
|
|
138
|
+
* The pictures a sheet adds to the drawing it kept from a file, laid out once that drawing's path in the
|
|
139
|
+
* package is known: each picture's media and link relationships go into `ledger`, the drawing's own,
|
|
140
|
+
* which already skips the ids the drawing holds.
|
|
141
|
+
*/
|
|
142
|
+
export type PicturesJoiningDrawing = (ledger: RelationshipLedger) => readonly DrawingImage[];
|
|
143
|
+
export declare function planPreservedParts(workbook: Workbook, generatedDrawingCount: number, generatedMediaCount: number, generatedPivotCount: number, pictures: ReadonlyMap<string, PicturesJoiningDrawing>): PreservedPlan;
|
|
144
|
+
export interface SheetPlan {
|
|
145
|
+
/** Every relationship the sheet's `.rels` part declares, in id order; empty when it needs none. */
|
|
146
|
+
readonly relationships: readonly PlannedRelationship[];
|
|
147
|
+
readonly tables: TablePlan[];
|
|
148
|
+
readonly drawing: DrawingPlan | null;
|
|
149
|
+
readonly comments: CommentPlan | null;
|
|
150
|
+
readonly threadedComments: ThreadedCommentPlan | null;
|
|
151
|
+
readonly printerSettings: PrinterSettingsPlan | null;
|
|
152
|
+
readonly hyperlinks: HyperlinkPlan[];
|
|
153
|
+
readonly background: BackgroundPlan | null;
|
|
154
|
+
readonly preservedRefs: PreservedReferencePlan[];
|
|
155
|
+
readonly pivots: PivotPlan[];
|
|
156
|
+
}
|