@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
|
@@ -3,20 +3,25 @@ import type { Worksheet } from '../../core/worksheet.ts';
|
|
|
3
3
|
import { type CollectingPass } from '../../xml/xml-read.ts';
|
|
4
4
|
/** The standard `<dataValidations>` element for the rules stored in the legacy form, or '' when the
|
|
5
5
|
* sheet has none of them, so a sheet with only extended (or no) validations stays byte-clean here.
|
|
6
|
-
* The extended rules are emitted separately by {@link dataValidationsExtXml}.
|
|
7
|
-
|
|
6
|
+
* The extended rules are emitted separately by {@link dataValidationsExtXml}.
|
|
7
|
+
*
|
|
8
|
+
* An operand is stored with the function prefixes a cell formula takes, as Excel stores it;
|
|
9
|
+
* `formulaNames` is `formulaNamesInScope` for the sheet. */
|
|
10
|
+
export declare function dataValidationsXml(entries: readonly DataValidationEntry[], formulaNames: ReadonlySet<string>): string;
|
|
8
11
|
/** The `<ext>` carrying the extended (`<x14:dataValidation>`) rules, or '' when the sheet declares
|
|
9
12
|
* none. Emitted bare (no `<extLst>` wrapper) so the worksheet serialiser can gather it into a single
|
|
10
13
|
* `<extLst>` beside the conditional-formatting extension: a worksheet may carry at most one. */
|
|
11
|
-
export declare function dataValidationsExtXml(entries: readonly DataValidationEntry[]): string;
|
|
14
|
+
export declare function dataValidationsExtXml(entries: readonly DataValidationEntry[], formulaNames: ReadonlySet<string>): string;
|
|
12
15
|
/** A pass gathering the standard `<dataValidation>` elements of a worksheet part, for a caller
|
|
13
|
-
* reading the part alongside its other readers in one parse.
|
|
14
|
-
|
|
16
|
+
* reading the part alongside its other readers in one parse. An operand sheds its function prefixes
|
|
17
|
+
* against `definedNames`, the workbook's names as `definedNameKeys` spells them. */
|
|
18
|
+
export declare function dataValidationPass(definedNames: ReadonlySet<string>): CollectingPass<DataValidationEntry[]>;
|
|
15
19
|
/** A pass gathering the extended `<x14:dataValidation>` elements of a worksheet's `<extLst>`, so a
|
|
16
20
|
* cross-sheet or whole-column list validation Excel stored only in the 2009 extension form is read
|
|
17
21
|
* back rather than dropped. The standard pass ignores these (they are prefixed); this one,
|
|
18
|
-
* symmetrically, handles only the prefixed elements.
|
|
19
|
-
|
|
22
|
+
* symmetrically, handles only the prefixed elements. An operand sheds its function prefixes against
|
|
23
|
+
* `definedNames`, as the standard pass's does. */
|
|
24
|
+
export declare function extendedDataValidationPass(definedNames: ReadonlySet<string>): CollectingPass<DataValidationEntry[]>;
|
|
20
25
|
/** Fold parsed validations onto a sheet, each bound to its original range and carrying its form: an
|
|
21
26
|
* `extended` entry is re-attached as extended so a round-trip writes it back to the x14 block. */
|
|
22
27
|
export declare function applyDataValidations(sheet: Worksheet, entries: readonly DataValidationEntry[]): void;
|
|
@@ -1,23 +1,30 @@
|
|
|
1
|
-
import { isDataValidationErrorStyle, isDataValidationOperator, isDataValidationType, } from '../../core/data-validation.js';
|
|
1
|
+
import { isDataValidationErrorStyle, isDataValidationImeMode, isDataValidationOperator, isDataValidationType, } from '../../core/data-validation.js';
|
|
2
|
+
import { mangleFormula, stripFormulaEquals, unmangleFunctions } from '../../core/formula.js';
|
|
2
3
|
import { decodeSqrefRects } from '../../core/merge.js';
|
|
4
|
+
import { coerceNumericLiteral, enumToken } from '../../xml/xml-attrs.js';
|
|
3
5
|
import { TextCapture } from '../../xml/xml-read.js';
|
|
4
|
-
import { boolStrict,
|
|
5
|
-
import { checkedToken, escapeAttr, escapeText,
|
|
6
|
-
import {
|
|
6
|
+
import { boolStrict, localName } from '../../xml/xml-scan.js';
|
|
7
|
+
import { checkedToken, escapeAttr, escapeText, textAttr } from '../../xml/xml.js';
|
|
8
|
+
import { admitting } from '../read-policy/read-repair.js';
|
|
9
|
+
import { DATA_VALIDATION_EXT_URI, isExtensionElement, isMainNamespaceElement, XM_NS, } from './namespaces.js';
|
|
7
10
|
import { x14Ext } from './x14-ext.js';
|
|
8
11
|
const TYPED = new Set(['whole', 'decimal', 'date', 'time', 'textLength']);
|
|
9
|
-
export function dataValidationsXml(entries) {
|
|
12
|
+
export function dataValidationsXml(entries, formulaNames) {
|
|
10
13
|
const standard = entries.filter((entry) => !entry.extended);
|
|
11
14
|
if (standard.length === 0)
|
|
12
15
|
return '';
|
|
13
|
-
const items = standard
|
|
16
|
+
const items = standard
|
|
17
|
+
.map(({ sqref, rule }) => dataValidationXml(sqref, rule, formulaNames))
|
|
18
|
+
.join('');
|
|
14
19
|
return `<dataValidations count="${standard.length}">${items}</dataValidations>`;
|
|
15
20
|
}
|
|
16
|
-
export function dataValidationsExtXml(entries) {
|
|
21
|
+
export function dataValidationsExtXml(entries, formulaNames) {
|
|
17
22
|
const extended = entries.filter((entry) => entry.extended);
|
|
18
23
|
if (extended.length === 0)
|
|
19
24
|
return '';
|
|
20
|
-
const items = extended
|
|
25
|
+
const items = extended
|
|
26
|
+
.map(({ sqref, rule }) => extendedDataValidationXml(sqref, rule, formulaNames))
|
|
27
|
+
.join('');
|
|
21
28
|
return x14Ext(DATA_VALIDATION_EXT_URI, `<x14:dataValidations count="${extended.length}" xmlns:xm="${XM_NS}">${items}</x14:dataValidations>`);
|
|
22
29
|
}
|
|
23
30
|
function ruleAttrs(rule) {
|
|
@@ -25,10 +32,14 @@ function ruleAttrs(rule) {
|
|
|
25
32
|
(rule.errorStyle === undefined
|
|
26
33
|
? ''
|
|
27
34
|
: ` errorStyle="${checkedToken(rule.errorStyle, isDataValidationErrorStyle, 'data validation error style')}"`) +
|
|
35
|
+
(rule.imeMode === undefined
|
|
36
|
+
? ''
|
|
37
|
+
: ` imeMode="${checkedToken(rule.imeMode, isDataValidationImeMode, 'data validation IME mode')}"`) +
|
|
28
38
|
(rule.operator === undefined
|
|
29
39
|
? ''
|
|
30
40
|
: ` operator="${checkedToken(rule.operator, isDataValidationOperator, 'data validation operator')}"`) +
|
|
31
41
|
(rule.allowBlank ? ' allowBlank="1"' : '') +
|
|
42
|
+
(rule.suppressDropDown ? ' showDropDown="1"' : '') +
|
|
32
43
|
(rule.showInputMessage ? ' showInputMessage="1"' : '') +
|
|
33
44
|
(rule.showErrorMessage ? ' showErrorMessage="1"' : '') +
|
|
34
45
|
textAttr('errorTitle', rule.errorTitle) +
|
|
@@ -36,60 +47,54 @@ function ruleAttrs(rule) {
|
|
|
36
47
|
textAttr('promptTitle', rule.promptTitle) +
|
|
37
48
|
textAttr('prompt', rule.prompt));
|
|
38
49
|
}
|
|
39
|
-
function dataValidationXml(sqref, rule) {
|
|
40
|
-
const [f1, f2] =
|
|
41
|
-
const body = (f1 !== undefined ? `<formula1>${
|
|
42
|
-
(f2 !== undefined ? `<formula2>${
|
|
50
|
+
function dataValidationXml(sqref, rule, formulaNames) {
|
|
51
|
+
const [f1, f2] = rule.formulae ?? [];
|
|
52
|
+
const body = (f1 !== undefined ? `<formula1>${operandText(f1, formulaNames)}</formula1>` : '') +
|
|
53
|
+
(f2 !== undefined ? `<formula2>${operandText(f2, formulaNames)}</formula2>` : '');
|
|
43
54
|
return `<dataValidation${ruleAttrs(rule)} sqref="${escapeAttr(sqref)}">${body}</dataValidation>`;
|
|
44
55
|
}
|
|
45
|
-
function
|
|
46
|
-
const drop = (v) => typeof v === 'number' && !Number.isFinite(v) ? undefined : v;
|
|
56
|
+
function extendedDataValidationXml(sqref, rule, formulaNames) {
|
|
47
57
|
const [f1, f2] = rule.formulae ?? [];
|
|
48
|
-
return [drop(f1), drop(f2)];
|
|
49
|
-
}
|
|
50
|
-
function extendedDataValidationXml(sqref, rule) {
|
|
51
|
-
const [f1, f2] = operands(rule);
|
|
52
58
|
const body = (f1 !== undefined
|
|
53
|
-
? `<x14:formula1><xm:f>${
|
|
59
|
+
? `<x14:formula1><xm:f>${operandText(f1, formulaNames)}</xm:f></x14:formula1>`
|
|
54
60
|
: '') +
|
|
55
61
|
(f2 !== undefined
|
|
56
|
-
? `<x14:formula2><xm:f>${
|
|
62
|
+
? `<x14:formula2><xm:f>${operandText(f2, formulaNames)}</xm:f></x14:formula2>`
|
|
57
63
|
: '') +
|
|
58
64
|
`<xm:sqref>${escapeText(sqref)}</xm:sqref>`;
|
|
59
65
|
return `<x14:dataValidation${ruleAttrs(rule)}>${body}</x14:dataValidation>`;
|
|
60
66
|
}
|
|
61
|
-
|
|
67
|
+
function operandText(operand, formulaNames) {
|
|
68
|
+
return escapeText(mangleFormula(stripFormulaEquals(operand), formulaNames));
|
|
69
|
+
}
|
|
70
|
+
const FORMULA_ELEMENTS = new Set(['formula1', 'formula2']);
|
|
71
|
+
export function dataValidationPass(definedNames) {
|
|
62
72
|
const entries = [];
|
|
63
73
|
let current;
|
|
64
|
-
|
|
74
|
+
const formula = new TextCapture(FORMULA_ELEMENTS);
|
|
65
75
|
const handlers = {
|
|
66
|
-
onOpen(name, attrs) {
|
|
76
|
+
onOpen(name, attrs, selfClosing, scope) {
|
|
67
77
|
const ln = localName(name);
|
|
68
|
-
if (ln === 'dataValidation' &&
|
|
78
|
+
if (ln === 'dataValidation' && isMainNamespaceElement(scope, name)) {
|
|
69
79
|
current = { attrs, formulae: [] };
|
|
70
80
|
}
|
|
71
|
-
else if (current !== undefined
|
|
72
|
-
|
|
73
|
-
current.formulae[0] = '';
|
|
74
|
-
}
|
|
75
|
-
else if (current !== undefined && ln === 'formula2') {
|
|
76
|
-
slot = 1;
|
|
77
|
-
current.formulae[1] = '';
|
|
81
|
+
else if (current !== undefined) {
|
|
82
|
+
formula.open(ln, selfClosing);
|
|
78
83
|
}
|
|
79
84
|
},
|
|
80
85
|
onText(text) {
|
|
81
|
-
|
|
82
|
-
current.formulae[slot] = (current.formulae[slot] ?? '') + text;
|
|
83
|
-
}
|
|
86
|
+
formula.text(text);
|
|
84
87
|
},
|
|
85
88
|
onClose(name) {
|
|
86
89
|
const ln = localName(name);
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
const text = formula.close(ln);
|
|
91
|
+
if (text !== undefined) {
|
|
92
|
+
if (current !== undefined)
|
|
93
|
+
current.formulae[ln === 'formula1' ? 0 : 1] = text;
|
|
89
94
|
return;
|
|
90
95
|
}
|
|
91
96
|
if (ln === 'dataValidation' && current !== undefined) {
|
|
92
|
-
const built = buildEntry(current.attrs, current.formulae);
|
|
97
|
+
const built = buildEntry(current.attrs, current.formulae, definedNames);
|
|
93
98
|
if (built !== undefined)
|
|
94
99
|
entries.push(built);
|
|
95
100
|
current = undefined;
|
|
@@ -98,14 +103,14 @@ export function dataValidationPass() {
|
|
|
98
103
|
};
|
|
99
104
|
return { handlers, result: () => entries };
|
|
100
105
|
}
|
|
101
|
-
function buildEntry(attrs, formulae) {
|
|
106
|
+
function buildEntry(attrs, formulae, definedNames) {
|
|
102
107
|
const { sqref } = attrs;
|
|
103
108
|
if (sqref === undefined)
|
|
104
109
|
return undefined;
|
|
105
|
-
const rule = buildRule(attrs, formulae);
|
|
110
|
+
const rule = buildRule(attrs, formulae, definedNames);
|
|
106
111
|
return rule === undefined ? undefined : { sqref, rule };
|
|
107
112
|
}
|
|
108
|
-
function buildRule(attrs, formulae) {
|
|
113
|
+
function buildRule(attrs, formulae, definedNames) {
|
|
109
114
|
const { type } = attrs;
|
|
110
115
|
if (type === undefined || !isDataValidationType(type))
|
|
111
116
|
return undefined;
|
|
@@ -119,12 +124,17 @@ function buildRule(attrs, formulae) {
|
|
|
119
124
|
}
|
|
120
125
|
if (boolStrict(attrs.allowBlank))
|
|
121
126
|
rule.allowBlank = true;
|
|
127
|
+
if (boolStrict(attrs.showDropDown))
|
|
128
|
+
rule.suppressDropDown = true;
|
|
122
129
|
if (boolStrict(attrs.showInputMessage))
|
|
123
130
|
rule.showInputMessage = true;
|
|
124
131
|
if (boolStrict(attrs.showErrorMessage))
|
|
125
132
|
rule.showErrorMessage = true;
|
|
126
133
|
if (attrs.errorStyle !== undefined && isDataValidationErrorStyle(attrs.errorStyle))
|
|
127
134
|
rule.errorStyle = attrs.errorStyle;
|
|
135
|
+
const imeMode = enumToken(attrs.imeMode, isDataValidationImeMode);
|
|
136
|
+
if (imeMode !== undefined)
|
|
137
|
+
rule.imeMode = imeMode;
|
|
128
138
|
if (attrs.error !== undefined)
|
|
129
139
|
rule.error = attrs.error;
|
|
130
140
|
if (attrs.errorTitle !== undefined)
|
|
@@ -135,27 +145,28 @@ function buildRule(attrs, formulae) {
|
|
|
135
145
|
rule.promptTitle = attrs.promptTitle;
|
|
136
146
|
const parsed = formulae
|
|
137
147
|
.filter((f) => f !== undefined)
|
|
148
|
+
.map((f) => unmangleFunctions(f, definedNames))
|
|
138
149
|
.map((f) => (type === 'list' || type === 'custom' ? f : coerceNumericLiteral(f)));
|
|
139
150
|
if (parsed.length > 0)
|
|
140
151
|
rule.formulae = parsed;
|
|
141
152
|
return rule;
|
|
142
153
|
}
|
|
143
|
-
export function extendedDataValidationPass() {
|
|
154
|
+
export function extendedDataValidationPass(definedNames) {
|
|
144
155
|
const entries = [];
|
|
145
156
|
let current;
|
|
146
157
|
let slot;
|
|
147
158
|
const capture = new TextCapture(['f', 'sqref']);
|
|
148
159
|
const handlers = {
|
|
149
|
-
onOpen(name, attrs, selfClosing) {
|
|
160
|
+
onOpen(name, attrs, selfClosing, scope) {
|
|
150
161
|
const ln = localName(name);
|
|
151
|
-
const
|
|
152
|
-
if (ln === 'dataValidation' &&
|
|
162
|
+
const extension = isExtensionElement(scope, name);
|
|
163
|
+
if (ln === 'dataValidation' && extension) {
|
|
153
164
|
current = { attrs, formulae: [], sqref: '' };
|
|
154
165
|
}
|
|
155
|
-
else if (current !== undefined &&
|
|
166
|
+
else if (current !== undefined && extension && ln === 'formula1') {
|
|
156
167
|
slot = 0;
|
|
157
168
|
}
|
|
158
|
-
else if (current !== undefined &&
|
|
169
|
+
else if (current !== undefined && extension && ln === 'formula2') {
|
|
159
170
|
slot = 1;
|
|
160
171
|
}
|
|
161
172
|
else if (current !== undefined) {
|
|
@@ -165,8 +176,9 @@ export function extendedDataValidationPass() {
|
|
|
165
176
|
onText(chunk) {
|
|
166
177
|
capture.text(chunk);
|
|
167
178
|
},
|
|
168
|
-
onClose(name) {
|
|
179
|
+
onClose(name, scope) {
|
|
169
180
|
const ln = localName(name);
|
|
181
|
+
const extension = isExtensionElement(scope, name);
|
|
170
182
|
const text = capture.close(ln);
|
|
171
183
|
if (text !== undefined) {
|
|
172
184
|
if (ln === 'f') {
|
|
@@ -177,11 +189,11 @@ export function extendedDataValidationPass() {
|
|
|
177
189
|
current.sqref = text;
|
|
178
190
|
}
|
|
179
191
|
}
|
|
180
|
-
else if ((ln === 'formula1' || ln === 'formula2') &&
|
|
192
|
+
else if ((ln === 'formula1' || ln === 'formula2') && extension) {
|
|
181
193
|
slot = undefined;
|
|
182
194
|
}
|
|
183
|
-
else if (ln === 'dataValidation' &&
|
|
184
|
-
const built = buildExtendedEntry(current.attrs, current.formulae, current.sqref);
|
|
195
|
+
else if (ln === 'dataValidation' && extension && current !== undefined) {
|
|
196
|
+
const built = buildExtendedEntry(current.attrs, current.formulae, current.sqref, definedNames);
|
|
185
197
|
if (built !== undefined)
|
|
186
198
|
entries.push(built);
|
|
187
199
|
current = undefined;
|
|
@@ -190,16 +202,18 @@ export function extendedDataValidationPass() {
|
|
|
190
202
|
};
|
|
191
203
|
return { handlers, result: () => entries };
|
|
192
204
|
}
|
|
193
|
-
function buildExtendedEntry(attrs, formulae, sqref) {
|
|
205
|
+
function buildExtendedEntry(attrs, formulae, sqref, definedNames) {
|
|
194
206
|
if (sqref === '')
|
|
195
207
|
return undefined;
|
|
196
|
-
const rule = buildRule(attrs, formulae);
|
|
208
|
+
const rule = buildRule(attrs, formulae, definedNames);
|
|
197
209
|
return rule === undefined ? undefined : { sqref, rule, extended: true };
|
|
198
210
|
}
|
|
199
211
|
export function applyDataValidations(sheet, entries) {
|
|
200
212
|
for (const { sqref, rule, extended } of entries) {
|
|
201
213
|
if (decodeSqrefRects(sqref).length === 0)
|
|
202
214
|
continue;
|
|
203
|
-
|
|
215
|
+
admitting(() => {
|
|
216
|
+
sheet.addDataValidation(sqref, rule, extended ? { extended: true } : {});
|
|
217
|
+
});
|
|
204
218
|
}
|
|
205
219
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type VbaLibraryReference } from '../../vba/project-editor.ts';
|
|
2
|
+
import { type ReadPackageOptions } from '../opc/read-options.ts';
|
|
2
3
|
/**
|
|
3
4
|
* Remove a standard module from an existing macro-enabled package's VBA project, returning new package
|
|
4
5
|
* bytes. Every part but `xl/vbaProject.bin` is preserved byte-for-byte (see {@link removeVbaModule} for
|
|
@@ -8,8 +9,10 @@ import { type VbaLibraryReference } from '../../vba/project-editor.ts';
|
|
|
8
9
|
* @throws {VbaAuthorError} if the package carries no VBA project, `name` is not in the project, or names
|
|
9
10
|
* a `document`/`designer` module.
|
|
10
11
|
* @throws {VbaParseError} if the attached `vbaProject.bin` is malformed.
|
|
12
|
+
* @throws {PackageReadError} if the input is not a readable ZIP, or exceeds the inflate bound
|
|
13
|
+
* ({@link ReadPackageOptions.maxUncompressedBytes}, defaulting as `readXlsx` does).
|
|
11
14
|
*/
|
|
12
|
-
export declare function editXlsxVbaRemoveModule(xlsx: Uint8Array, name: string): Uint8Array;
|
|
15
|
+
export declare function editXlsxVbaRemoveModule(xlsx: Uint8Array, name: string, options?: ReadPackageOptions): Uint8Array;
|
|
13
16
|
/**
|
|
14
17
|
* Add a registered (COM type-library) reference to an existing macro-enabled package's VBA project,
|
|
15
18
|
* returning new package bytes. Every part but `xl/vbaProject.bin` is preserved byte-for-byte (see
|
|
@@ -19,5 +22,7 @@ export declare function editXlsxVbaRemoveModule(xlsx: Uint8Array, name: string):
|
|
|
19
22
|
* @throws {VbaAuthorError} if the package carries no VBA project, or any field of `ref` is invalid (see
|
|
20
23
|
* {@link VbaLibraryReference}).
|
|
21
24
|
* @throws {VbaParseError} if the attached `vbaProject.bin` is malformed.
|
|
25
|
+
* @throws {PackageReadError} if the input is not a readable ZIP, or exceeds the inflate bound
|
|
26
|
+
* ({@link ReadPackageOptions.maxUncompressedBytes}, defaulting as `readXlsx` does).
|
|
22
27
|
*/
|
|
23
|
-
export declare function editXlsxVbaAddReference(xlsx: Uint8Array, ref: VbaLibraryReference): Uint8Array;
|
|
28
|
+
export declare function editXlsxVbaAddReference(xlsx: Uint8Array, ref: VbaLibraryReference, options?: ReadPackageOptions): Uint8Array;
|
package/dist/io/xlsx/edit-vba.js
CHANGED
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { strToU8, zipSync } from 'fflate';
|
|
2
2
|
import { VbaAuthorError } from '../../vba/errors.js';
|
|
3
3
|
import { addVbaReference, removeVbaModule, } from '../../vba/project-editor.js';
|
|
4
|
+
import { elementRange } from '../../xml/xml-read.js';
|
|
4
5
|
import { relsPathFor, resolveRelativePart } from '../opc/part-paths.js';
|
|
5
|
-
import { parseRelationshipRecords,
|
|
6
|
+
import { packageAccessors, parseRelationshipRecords, readPartRelationships, } from '../opc/read-opc.js';
|
|
7
|
+
import { DEFAULT_MAX_UNCOMPRESSED } from '../opc/read-options.js';
|
|
8
|
+
import { inflateSpreadsheetPackage } from '../opc/sniff-format.js';
|
|
6
9
|
import { FIXED_ENTRY_MTIME } from '../opc/zip-mtime.js';
|
|
7
10
|
const OFFICE_DOCUMENT_REL = 'officeDocument';
|
|
8
11
|
const VBA_PROJECT_REL = 'vbaProject';
|
|
9
12
|
const VBA_SIGNATURE_REL_INFIX = 'vbaProjectSignature';
|
|
10
|
-
export function editXlsxVbaRemoveModule(xlsx, name) {
|
|
11
|
-
return applyToVbaProjectPart(xlsx, (bin) => removeVbaModule(bin, name));
|
|
13
|
+
export function editXlsxVbaRemoveModule(xlsx, name, options = {}) {
|
|
14
|
+
return applyToVbaProjectPart(xlsx, options, (bin) => removeVbaModule(bin, name));
|
|
12
15
|
}
|
|
13
|
-
export function editXlsxVbaAddReference(xlsx, ref) {
|
|
14
|
-
return applyToVbaProjectPart(xlsx, (bin) => addVbaReference(bin, ref));
|
|
16
|
+
export function editXlsxVbaAddReference(xlsx, ref, options = {}) {
|
|
17
|
+
return applyToVbaProjectPart(xlsx, options, (bin) => addVbaReference(bin, ref));
|
|
15
18
|
}
|
|
16
|
-
function applyToVbaProjectPart(xlsx, apply) {
|
|
17
|
-
const files =
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
19
|
+
function applyToVbaProjectPart(xlsx, options, apply) {
|
|
20
|
+
const files = inflateSpreadsheetPackage(xlsx, options.maxUncompressedBytes ?? DEFAULT_MAX_UNCOMPRESSED);
|
|
21
|
+
const pkg = packageAccessors(files);
|
|
22
|
+
const binPath = locateVbaProjectPart(pkg);
|
|
23
|
+
const binKey = binPath === undefined ? undefined : pkg.partKey(binPath);
|
|
24
|
+
const bin = binKey === undefined ? undefined : files[binKey];
|
|
25
|
+
if (binPath === undefined || binKey === undefined || bin === undefined) {
|
|
21
26
|
throw new VbaAuthorError('package has no VBA project to edit');
|
|
22
27
|
}
|
|
23
|
-
files[
|
|
24
|
-
dropStaleSignature(files, binPath);
|
|
28
|
+
files[binKey] = apply(bin);
|
|
29
|
+
dropStaleSignature(files, pkg, binPath);
|
|
25
30
|
return zipSync(files, { mtime: FIXED_ENTRY_MTIME });
|
|
26
31
|
}
|
|
27
|
-
function locateVbaProjectPart(
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
32
|
+
function locateVbaProjectPart(pkg) {
|
|
33
|
+
const workbookPath = readPartRelationships('', pkg.partText).targetPath(OFFICE_DOCUMENT_REL);
|
|
34
|
+
if (workbookPath === undefined)
|
|
30
35
|
return undefined;
|
|
31
|
-
|
|
32
|
-
if (workbookTarget === undefined)
|
|
33
|
-
return undefined;
|
|
34
|
-
const workbookPath = resolveRelativePart('', workbookTarget);
|
|
35
|
-
const workbookRels = textPart(files, relsPathFor(workbookPath));
|
|
36
|
-
if (workbookRels === undefined)
|
|
37
|
-
return undefined;
|
|
38
|
-
const vbaTarget = relationshipTargetByType(workbookRels, VBA_PROJECT_REL);
|
|
39
|
-
if (vbaTarget === undefined)
|
|
40
|
-
return undefined;
|
|
41
|
-
return resolveRelativePart(workbookPath, vbaTarget);
|
|
36
|
+
return readPartRelationships(workbookPath, pkg.partText).targetPath(VBA_PROJECT_REL);
|
|
42
37
|
}
|
|
43
|
-
function dropStaleSignature(files, binPath) {
|
|
44
|
-
const
|
|
45
|
-
const binRels =
|
|
46
|
-
if (binRels === undefined)
|
|
38
|
+
function dropStaleSignature(files, pkg, binPath) {
|
|
39
|
+
const binRelsKey = pkg.partKey(relsPathFor(binPath));
|
|
40
|
+
const binRels = binRelsKey === undefined ? undefined : pkg.partText(binRelsKey);
|
|
41
|
+
if (binRelsKey === undefined || binRels === undefined)
|
|
47
42
|
return;
|
|
48
43
|
const signatureRels = parseRelationshipRecords(binRels).filter((rel) => !rel.external && rel.type.includes(VBA_SIGNATURE_REL_INFIX));
|
|
49
44
|
if (signatureRels.length === 0)
|
|
50
45
|
return;
|
|
51
|
-
|
|
46
|
+
const contentTypesKey = pkg.partKey(CONTENT_TYPES_PART);
|
|
47
|
+
let contentTypes = contentTypesKey === undefined ? undefined : pkg.partText(contentTypesKey);
|
|
52
48
|
let rels = binRels;
|
|
53
49
|
for (const rel of signatureRels) {
|
|
54
50
|
const partPath = resolveRelativePart(binPath, rel.target);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
const partKey = pkg.partKey(partPath);
|
|
52
|
+
if (partKey !== undefined)
|
|
53
|
+
delete files[partKey];
|
|
54
|
+
const partName = `/${partPath}`.toLowerCase();
|
|
55
|
+
rels = removeElements(rels, 'Relationship', (attrs) => attrs.Id === rel.id);
|
|
56
|
+
if (contentTypes !== undefined) {
|
|
57
|
+
contentTypes = removeElements(contentTypes, 'Override', (attrs) => attrs.PartName?.toLowerCase() === partName);
|
|
58
|
+
}
|
|
59
59
|
}
|
|
60
60
|
if (parseRelationshipRecords(rels).length === 0)
|
|
61
|
-
delete files[
|
|
61
|
+
delete files[binRelsKey];
|
|
62
62
|
else
|
|
63
|
-
files[
|
|
64
|
-
if (contentTypes !== undefined)
|
|
65
|
-
files[
|
|
66
|
-
}
|
|
67
|
-
function textPart(files, path) {
|
|
68
|
-
const bytes = files[path];
|
|
69
|
-
return bytes === undefined ? undefined : strFromU8(bytes);
|
|
70
|
-
}
|
|
71
|
-
function removeRelationshipById(xml, id) {
|
|
72
|
-
return xml.replace(/<Relationship\b[^>]*?\/>|<Relationship\b[\s\S]*?<\/Relationship>/g, (element) => (new RegExp(`\\bId="${escapeRegExp(id)}"`).test(element) ? '' : element));
|
|
73
|
-
}
|
|
74
|
-
function removeContentTypeOverride(xml, partPath) {
|
|
75
|
-
return xml.replace(/<Override\b[^>]*?\/>/g, (element) => element.includes(`PartName="/${partPath}"`) ? '' : element);
|
|
63
|
+
files[binRelsKey] = strToU8(rels);
|
|
64
|
+
if (contentTypesKey !== undefined && contentTypes !== undefined) {
|
|
65
|
+
files[contentTypesKey] = strToU8(contentTypes);
|
|
66
|
+
}
|
|
76
67
|
}
|
|
77
|
-
|
|
78
|
-
|
|
68
|
+
const CONTENT_TYPES_PART = '[Content_Types].xml';
|
|
69
|
+
function removeElements(xml, local, drop) {
|
|
70
|
+
let kept = '';
|
|
71
|
+
let rest = xml;
|
|
72
|
+
let range = elementRange(rest, [local]);
|
|
73
|
+
while (range !== undefined) {
|
|
74
|
+
kept += rest.slice(0, drop(range.attrs) ? range.start : range.end);
|
|
75
|
+
rest = rest.slice(range.end);
|
|
76
|
+
range = elementRange(rest, [local]);
|
|
77
|
+
}
|
|
78
|
+
return kept + rest;
|
|
79
79
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Font } from '../../core/style.ts';
|
|
2
|
+
import { type XmlAttributes } from '../../xml/xml-scan.ts';
|
|
3
|
+
export type FontDraft = {
|
|
4
|
+
-readonly [K in keyof Font]?: Font[K];
|
|
5
|
+
};
|
|
6
|
+
export declare function applyFontChild(draft: FontDraft, local: string, attrs: XmlAttributes): void;
|
|
7
|
+
export declare function fontXml(font: Font, nameTag?: 'name' | 'rFont'): string;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { isFontScheme, isFontVerticalAlignment, isNamedUnderlineStyle, } from '../../core/style.js';
|
|
2
|
+
import { numFinite, numInteger } from '../../xml/xml-attrs.js';
|
|
3
|
+
import { boolPresent } from '../../xml/xml-scan.js';
|
|
4
|
+
import { checkedToken, escapeAttr, numberText } from '../../xml/xml.js';
|
|
5
|
+
import { colorAttrs, parseColor } from './color-xml.js';
|
|
6
|
+
export function applyFontChild(draft, local, attrs) {
|
|
7
|
+
switch (local) {
|
|
8
|
+
case 'b':
|
|
9
|
+
draft.bold = boolPresent(attrs.val);
|
|
10
|
+
break;
|
|
11
|
+
case 'i':
|
|
12
|
+
draft.italic = boolPresent(attrs.val);
|
|
13
|
+
break;
|
|
14
|
+
case 'strike':
|
|
15
|
+
draft.strike = boolPresent(attrs.val);
|
|
16
|
+
break;
|
|
17
|
+
case 'outline':
|
|
18
|
+
draft.outline = boolPresent(attrs.val);
|
|
19
|
+
break;
|
|
20
|
+
case 'u':
|
|
21
|
+
draft.underline =
|
|
22
|
+
attrs.val === undefined
|
|
23
|
+
? true
|
|
24
|
+
: attrs.val === 'none'
|
|
25
|
+
? false
|
|
26
|
+
: isNamedUnderlineStyle(attrs.val)
|
|
27
|
+
? attrs.val
|
|
28
|
+
: true;
|
|
29
|
+
break;
|
|
30
|
+
case 'vertAlign':
|
|
31
|
+
if (attrs.val !== undefined && isFontVerticalAlignment(attrs.val))
|
|
32
|
+
draft.vertAlign = attrs.val;
|
|
33
|
+
break;
|
|
34
|
+
case 'sz': {
|
|
35
|
+
const size = numFinite(attrs.val);
|
|
36
|
+
if (size !== undefined)
|
|
37
|
+
draft.size = size;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
case 'color':
|
|
41
|
+
draft.color = parseColor(attrs);
|
|
42
|
+
break;
|
|
43
|
+
case 'name':
|
|
44
|
+
case 'rFont':
|
|
45
|
+
if (attrs.val !== undefined)
|
|
46
|
+
draft.name = attrs.val;
|
|
47
|
+
break;
|
|
48
|
+
case 'family': {
|
|
49
|
+
const family = numInteger(attrs.val);
|
|
50
|
+
if (family !== undefined)
|
|
51
|
+
draft.family = family;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
case 'charset': {
|
|
55
|
+
const charset = numInteger(attrs.val);
|
|
56
|
+
if (charset !== undefined)
|
|
57
|
+
draft.charset = charset;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case 'scheme':
|
|
61
|
+
if (attrs.val !== undefined && isFontScheme(attrs.val))
|
|
62
|
+
draft.scheme = attrs.val;
|
|
63
|
+
break;
|
|
64
|
+
default:
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function fontXml(font, nameTag = 'name') {
|
|
69
|
+
const parts = [];
|
|
70
|
+
if (font.bold)
|
|
71
|
+
parts.push('<b/>');
|
|
72
|
+
if (font.italic)
|
|
73
|
+
parts.push('<i/>');
|
|
74
|
+
if (font.strike)
|
|
75
|
+
parts.push('<strike/>');
|
|
76
|
+
if (font.outline)
|
|
77
|
+
parts.push('<outline/>');
|
|
78
|
+
const underline = underlineXml(font.underline);
|
|
79
|
+
if (underline !== '')
|
|
80
|
+
parts.push(underline);
|
|
81
|
+
if (font.vertAlign !== undefined) {
|
|
82
|
+
parts.push(`<vertAlign val="${checkedToken(font.vertAlign, isFontVerticalAlignment, 'font vertical alignment')}"/>`);
|
|
83
|
+
}
|
|
84
|
+
if (font.size !== undefined)
|
|
85
|
+
parts.push(`<sz val="${numberText(font.size)}"/>`);
|
|
86
|
+
if (font.color !== undefined)
|
|
87
|
+
parts.push(`<color ${colorAttrs(font.color)}/>`);
|
|
88
|
+
if (font.name !== undefined)
|
|
89
|
+
parts.push(`<${nameTag} val="${escapeAttr(font.name)}"/>`);
|
|
90
|
+
if (font.family !== undefined)
|
|
91
|
+
parts.push(`<family val="${numberText(font.family)}"/>`);
|
|
92
|
+
if (font.charset !== undefined)
|
|
93
|
+
parts.push(`<charset val="${numberText(font.charset)}"/>`);
|
|
94
|
+
if (font.scheme !== undefined && font.scheme !== 'none')
|
|
95
|
+
parts.push(`<scheme val="${checkedToken(font.scheme, isFontScheme, 'font scheme')}"/>`);
|
|
96
|
+
return parts.join('');
|
|
97
|
+
}
|
|
98
|
+
function underlineXml(underline) {
|
|
99
|
+
if (underline === undefined || underline === false || underline === 'none')
|
|
100
|
+
return '';
|
|
101
|
+
if (underline === true || underline === 'single')
|
|
102
|
+
return '<u/>';
|
|
103
|
+
return `<u val="${checkedToken(underline, isNamedUnderlineStyle, 'underline style')}"/>`;
|
|
104
|
+
}
|
|
@@ -1,29 +1,26 @@
|
|
|
1
|
+
import type { Hyperlink } from '../../core/hyperlink.ts';
|
|
1
2
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
2
3
|
import { type CollectingPass } from '../../xml/xml-read.ts';
|
|
3
|
-
import type {
|
|
4
|
-
/** A hyperlink gathered from a sheet for serialisation: the cell it sits on, its target, and an
|
|
5
|
-
* optional tooltip. The visible label is the cell's own value and is serialised as that value. */
|
|
6
|
-
export interface CollectedHyperlink {
|
|
7
|
-
readonly ref: string;
|
|
8
|
-
readonly target: string;
|
|
9
|
-
readonly tooltip?: string;
|
|
10
|
-
}
|
|
4
|
+
import type { RelationshipLedger } from './package-plan.ts';
|
|
11
5
|
/** A hyperlink resolved for serialisation. An external target carries a `relId` (the sheet
|
|
12
|
-
* relationship holding the URL)
|
|
13
|
-
*
|
|
6
|
+
* relationship holding the URL); an internal target carries a `location` (the in-workbook
|
|
7
|
+
* reference). Exactly one of `relId`/`location` is ever set. */
|
|
14
8
|
export interface HyperlinkPlan {
|
|
15
9
|
readonly ref: string;
|
|
16
10
|
readonly relId?: string;
|
|
17
|
-
readonly target?: string;
|
|
18
11
|
readonly location?: string;
|
|
19
12
|
readonly tooltip?: string;
|
|
20
13
|
}
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Split a sheet's links into internal (location, no rel) and external (relationship) forms, recording
|
|
16
|
+
* each external link's URL in the sheet's ledger so its relationship follows every other sheet-local
|
|
17
|
+
* relationship in canonical order. An internal (`#`-prefixed) link records nothing.
|
|
18
|
+
*
|
|
19
|
+
* The links keep the order the sheet holds them in. That order is what decides which of two links over
|
|
20
|
+
* one cell `Worksheet.hyperlinkAt` reports, and a re-read adds them in document order, so writing them
|
|
21
|
+
* any other way would change the answer across a save.
|
|
22
|
+
*/
|
|
23
|
+
export declare function planHyperlinks(links: readonly Hyperlink[], rels: RelationshipLedger): HyperlinkPlan[];
|
|
27
24
|
/** The `<hyperlinks>` element, or '' when the sheet has none. Attribute order follows CT_Hyperlink:
|
|
28
25
|
* `ref`, `r:id`, `location`, `tooltip`. */
|
|
29
26
|
export declare function hyperlinksXml(links: readonly HyperlinkPlan[]): string;
|
|
@@ -38,9 +35,10 @@ interface ParsedHyperlink {
|
|
|
38
35
|
/** A pass gathering every `<hyperlink>` element of a worksheet part, for a caller reading the part
|
|
39
36
|
* alongside its other readers in one parse. */
|
|
40
37
|
export declare function sheetHyperlinkPass(): CollectingPass<ParsedHyperlink[]>;
|
|
41
|
-
/**
|
|
42
|
-
*
|
|
43
|
-
* URL for the external links hyperlinks almost always
|
|
44
|
-
* package rather than being handed over as a part path.
|
|
38
|
+
/**
|
|
39
|
+
* Put parsed hyperlinks on a sheet, in document order, whatever the cells they cover hold. `targetOf`
|
|
40
|
+
* resolves a relationship id to its raw Target: a URL for the external links hyperlinks almost always
|
|
41
|
+
* are, so it must stay unresolved against the package rather than being handed over as a part path.
|
|
42
|
+
*/
|
|
45
43
|
export declare function applyHyperlinks(sheet: Worksheet, links: readonly ParsedHyperlink[], targetOf: (relId: string) => string | undefined): void;
|
|
46
44
|
export {};
|