@shbernal/ts-xlsx 2.0.0 → 2.1.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.
Files changed (106) hide show
  1. package/README.md +20 -10
  2. package/dist/bytes.d.ts +24 -0
  3. package/dist/bytes.js +34 -0
  4. package/dist/core/address.d.ts +26 -4
  5. package/dist/core/address.js +21 -9
  6. package/dist/core/autofilter.d.ts +11 -0
  7. package/dist/core/autofilter.js +35 -10
  8. package/dist/core/color-resolution.d.ts +1 -1
  9. package/dist/core/color-resolution.js +7 -8
  10. package/dist/core/conditional-formatting-overlay.d.ts +5 -0
  11. package/dist/core/conditional-formatting-overlay.js +11 -0
  12. package/dist/core/conditional-formatting.d.ts +45 -5
  13. package/dist/core/conditional-formatting.js +88 -0
  14. package/dist/core/data-validation-overlay.d.ts +11 -0
  15. package/dist/core/data-validation-overlay.js +21 -2
  16. package/dist/core/data-validation.d.ts +9 -2
  17. package/dist/core/data-validation.js +34 -0
  18. package/dist/core/grid-edits.d.ts +16 -0
  19. package/dist/core/grid-edits.js +26 -8
  20. package/dist/core/grid-shift.d.ts +19 -0
  21. package/dist/core/grid-shift.js +8 -0
  22. package/dist/core/image.d.ts +2 -0
  23. package/dist/core/image.js +4 -0
  24. package/dist/core/merge.d.ts +12 -1
  25. package/dist/core/merge.js +36 -2
  26. package/dist/core/page-setup.d.ts +16 -2
  27. package/dist/core/page-setup.js +8 -1
  28. package/dist/core/pivot-table.d.ts +2 -0
  29. package/dist/core/pivot-table.js +25 -16
  30. package/dist/core/protection.d.ts +3 -0
  31. package/dist/core/protection.js +20 -14
  32. package/dist/core/row-input.d.ts +7 -0
  33. package/dist/core/row-input.js +10 -8
  34. package/dist/core/style.d.ts +27 -0
  35. package/dist/core/style.js +82 -67
  36. package/dist/core/table.d.ts +25 -11
  37. package/dist/core/table.js +67 -31
  38. package/dist/core/theme.d.ts +3 -1
  39. package/dist/core/theme.js +4 -0
  40. package/dist/core/workbook.d.ts +2 -2
  41. package/dist/core/worksheet-comments.d.ts +8 -0
  42. package/dist/core/worksheet-comments.js +18 -0
  43. package/dist/core/worksheet.d.ts +15 -2
  44. package/dist/core/worksheet.js +28 -48
  45. package/dist/customui/ribbon.js +24 -23
  46. package/dist/entries/core.d.ts +3 -3
  47. package/dist/entries/csv.d.ts +1 -1
  48. package/dist/entries/node-unavailable.d.ts +15 -0
  49. package/dist/entries/node-unavailable.js +20 -0
  50. package/dist/entries/node.d.ts +1 -0
  51. package/dist/entries/node.js +1 -0
  52. package/dist/entries/xlsx.d.ts +0 -1
  53. package/dist/entries/xlsx.js +0 -1
  54. package/dist/io/csv/read.js +1 -1
  55. package/dist/io/csv/write.d.ts +12 -2
  56. package/dist/io/csv/write.js +17 -2
  57. package/dist/io/opc/inflate.js +2 -12
  58. package/dist/io/opc/rels.d.ts +11 -0
  59. package/dist/io/opc/rels.js +3 -2
  60. package/dist/io/style/xf-style.d.ts +7 -2
  61. package/dist/io/style/xf-style.js +6 -1
  62. package/dist/io/xlsx/cell-accumulator.d.ts +1 -3
  63. package/dist/io/xlsx/cell-accumulator.js +20 -58
  64. package/dist/io/xlsx/cell-value.d.ts +1 -1
  65. package/dist/io/xlsx/cell-value.js +7 -4
  66. package/dist/io/xlsx/color-xml.d.ts +1 -1
  67. package/dist/io/xlsx/color-xml.js +7 -6
  68. package/dist/io/xlsx/comments.js +4 -2
  69. package/dist/io/xlsx/conditional-formatting.d.ts +1 -1
  70. package/dist/io/xlsx/conditional-formatting.js +60 -45
  71. package/dist/io/xlsx/data-validation.d.ts +1 -1
  72. package/dist/io/xlsx/data-validation.js +35 -33
  73. package/dist/io/xlsx/hyperlinks.js +6 -14
  74. package/dist/io/xlsx/images.js +19 -22
  75. package/dist/io/xlsx/read-pivot.js +2 -8
  76. package/dist/io/xlsx/read-shared-strings.js +8 -47
  77. package/dist/io/xlsx/read-styles.js +2 -1
  78. package/dist/io/xlsx/read-worksheet.js +14 -16
  79. package/dist/io/xlsx/read.d.ts +1 -1
  80. package/dist/io/xlsx/read.js +44 -74
  81. package/dist/io/xlsx/rich-runs.d.ts +41 -7
  82. package/dist/io/xlsx/rich-runs.js +94 -30
  83. package/dist/io/xlsx/sheet-properties.d.ts +1 -1
  84. package/dist/io/xlsx/sheet-properties.js +13 -9
  85. package/dist/io/xlsx/styles.d.ts +3 -15
  86. package/dist/io/xlsx/styles.js +63 -88
  87. package/dist/io/xlsx/tables.js +13 -13
  88. package/dist/io/xlsx/theme-xml.js +7 -4
  89. package/dist/io/xlsx/threaded-comments.js +19 -19
  90. package/dist/io/xlsx/workbook-xml.js +14 -8
  91. package/dist/io/xlsx/worksheet-xml.js +34 -37
  92. package/dist/io/xlsx/write-stream.d.ts +8 -1
  93. package/dist/io/xlsx/write-stream.js +10 -11
  94. package/dist/sha512.d.ts +2 -0
  95. package/dist/sha512.js +146 -0
  96. package/dist/vba/bytes.d.ts +1 -2
  97. package/dist/vba/bytes.js +1 -12
  98. package/dist/vba/dir-records.d.ts +53 -0
  99. package/dist/vba/dir-records.js +28 -0
  100. package/dist/vba/project-editor.js +5 -34
  101. package/dist/vba/project.js +2 -18
  102. package/dist/xml/xml-read.d.ts +60 -0
  103. package/dist/xml/xml-read.js +47 -0
  104. package/dist/xml/xml.d.ts +43 -1
  105. package/dist/xml/xml.js +17 -5
  106. package/package.json +21 -4
@@ -1,9 +1,10 @@
1
- import { decodeRange, MAX_COLUMN, MAX_ROW } from '../../core/address.js';
1
+ import { MAX_COLUMN, MAX_ROW, tryDecodeRange } from '../../core/address.js';
2
2
  import { isCustomFilterOperator, } from '../../core/autofilter.js';
3
3
  import { INTERNAL } from '../../core/internal.js';
4
+ import { isPageOrder, isPageOrientation, } from '../../core/page-setup.js';
4
5
  import { SHEET_PROTECTION_FLAGS, } from '../../core/protection.js';
5
6
  import { assignStyleFacets } from '../../core/style.js';
6
- import { boolPresent, boolStrict, boolTristate, decodeSpreadsheetText, localName, numFinite, numInteger, parseXml, } from '../../xml/xml-read.js';
7
+ import { boolPresent, boolStrict, boolTristate, decodeSpreadsheetText, enumToken, localName, numFinite, numInteger, parseXml, } from '../../xml/xml-read.js';
7
8
  import { CellAccumulator } from './cell-accumulator.js';
8
9
  import { parseColor } from './color-xml.js';
9
10
  const MARGIN_SIDES = ['left', 'right', 'top', 'bottom', 'header', 'footer'];
@@ -90,13 +91,13 @@ class AutoFilterAccumulator {
90
91
  commit(sheet) {
91
92
  if (this.#ref === null)
92
93
  return;
93
- try {
94
- const { left, right } = decodeRange(this.#ref);
95
- const width = left !== undefined && right !== undefined ? right - left + 1 : 0;
94
+ const decoded = tryDecodeRange(this.#ref);
95
+ const left = decoded?.left;
96
+ const right = decoded?.right;
97
+ if (left !== undefined && right !== undefined) {
98
+ const width = right - left + 1;
96
99
  sheet.autoFilter = { ref: this.#ref, columns: this.#columns.filter((c) => c.colId < width) };
97
100
  }
98
- catch {
99
- }
100
101
  this.#ref = null;
101
102
  this.#columns = [];
102
103
  }
@@ -214,9 +215,6 @@ export function parseWorksheet(xml, sheet, sharedStrings, xfStyles) {
214
215
  case 'customFilter':
215
216
  autoFilter.addCustom(attrs);
216
217
  break;
217
- default:
218
- cell.runs.applyProperty(local, attrs);
219
- break;
220
218
  }
221
219
  },
222
220
  onText(chunk) {
@@ -384,10 +382,10 @@ function applyPageSetup(pageSetup, attrs) {
384
382
  const fitToHeight = numInteger(attrs.fitToHeight, 0);
385
383
  if (fitToHeight !== undefined)
386
384
  pageSetup.fitToHeight = fitToHeight;
387
- if (attrs.pageOrder === 'downThenOver' || attrs.pageOrder === 'overThenDown') {
388
- pageSetup.pageOrder = attrs.pageOrder;
389
- }
390
- if (attrs.orientation === 'portrait' || attrs.orientation === 'landscape') {
391
- pageSetup.orientation = attrs.orientation;
392
- }
385
+ const pageOrder = enumToken(attrs.pageOrder, isPageOrder);
386
+ if (pageOrder !== undefined)
387
+ pageSetup.pageOrder = pageOrder;
388
+ const orientation = enumToken(attrs.orientation, isPageOrientation);
389
+ if (orientation !== undefined)
390
+ pageSetup.orientation = orientation;
393
391
  }
@@ -1,5 +1,5 @@
1
1
  import { Workbook, type WorkbookView } from '../../core/workbook.ts';
2
- import type { WorksheetState } from '../../core/worksheet.ts';
2
+ import { type WorksheetState } from '../../core/worksheet.ts';
3
3
  import { type ReadXlsxOptions } from '../opc/read-options.ts';
4
4
  export { parseRelationships, resolveWorkbookPart } from '../opc/read-opc.ts';
5
5
  export { DEFAULT_MAX_UNCOMPRESSED, type ReadXlsxOptions } from '../opc/read-options.ts';
@@ -3,7 +3,8 @@ import { unmangleFunctions } from '../../core/formula.js';
3
3
  import { INTERNAL } from '../../core/internal.js';
4
4
  import { WORKBOOK_PROTECTION_CREDENTIAL_ATTRS, } from '../../core/workbook-protection.js';
5
5
  import { Workbook } from '../../core/workbook.js';
6
- import { boolStrict, localName, numInteger, openElements, parseXml } from '../../xml/xml-read.js';
6
+ import { isVisibility } from '../../core/worksheet.js';
7
+ import { boolStrict, capturedText, enumToken, localName, numInteger, openElements, parseXml, } from '../../xml/xml-read.js';
7
8
  import { UnsupportedFormatError } from '../opc/errors.js';
8
9
  import { extensionOf } from '../opc/part-paths.js';
9
10
  import { capturePartClosure, contentTypeResolver, packageAccessors, parseRelationshipRecords, parseRelationships, readPartRelationships, relationshipTargetByType, resolveRelativePart, resolveWorkbookPart, } from '../opc/read-opc.js';
@@ -143,8 +144,19 @@ function readSheetPrinterSettings(sheetRels, pkg) {
143
144
  const path = sheetRels.targetPath('printerSettings');
144
145
  return path === undefined ? undefined : pkg.partBytes(path);
145
146
  }
147
+ function internImage(workbook, pkg, imageIdByMediaPath, mediaPath) {
148
+ const known = imageIdByMediaPath.get(mediaPath);
149
+ if (known !== undefined)
150
+ return known;
151
+ const bytes = pkg.partBytes(mediaPath);
152
+ if (bytes === undefined)
153
+ return undefined;
154
+ const id = workbook.addImage({ buffer: bytes, extension: extensionOf(mediaPath) });
155
+ imageIdByMediaPath.set(mediaPath, id);
156
+ return id;
157
+ }
146
158
  function readSheetImages(sheetRels, pkg, workbook, sheet, imageIdByMediaPath) {
147
- const { partText, partBytes } = pkg;
159
+ const { partText } = pkg;
148
160
  const drawingPath = sheetRels.targetPath('drawing');
149
161
  if (drawingPath === undefined)
150
162
  return;
@@ -159,14 +171,9 @@ function readSheetImages(sheetRels, pkg, workbook, sheet, imageIdByMediaPath) {
159
171
  if (embedded === undefined)
160
172
  continue;
161
173
  const mediaPath = drawingRels.pathOf(embedded.target);
162
- let id = imageIdByMediaPath.get(mediaPath);
163
- if (id === undefined) {
164
- const bytes = partBytes(mediaPath);
165
- if (bytes === undefined)
166
- continue;
167
- id = workbook.addImage({ buffer: bytes, extension: extensionOf(mediaPath) });
168
- imageIdByMediaPath.set(mediaPath, id);
169
- }
174
+ const id = internImage(workbook, pkg, imageIdByMediaPath, mediaPath);
175
+ if (id === undefined)
176
+ continue;
170
177
  const rot = anchor.rotation !== undefined ? { rotation: anchor.rotation } : {};
171
178
  if (anchor.to !== undefined) {
172
179
  const mode = anchor.editAs !== undefined ? { editAs: anchor.editAs } : {};
@@ -181,15 +188,9 @@ function readSheetBackground(sheetRels, pkg, workbook, sheet, imageIdByMediaPath
181
188
  const mediaPath = sheetRels.targetPath('image');
182
189
  if (mediaPath === undefined)
183
190
  return;
184
- let id = imageIdByMediaPath.get(mediaPath);
185
- if (id === undefined) {
186
- const bytes = pkg.partBytes(mediaPath);
187
- if (bytes === undefined)
188
- return;
189
- id = workbook.addImage({ buffer: bytes, extension: extensionOf(mediaPath) });
190
- imageIdByMediaPath.set(mediaPath, id);
191
- }
192
- sheet.addBackgroundImage(id);
191
+ const id = internImage(workbook, pkg, imageIdByMediaPath, mediaPath);
192
+ if (id !== undefined)
193
+ sheet.addBackgroundImage(id);
193
194
  }
194
195
  function readSheetPreservedReferences(sheetRels, sheetXml, pkg, contentTypeOf, sheet) {
195
196
  const { partText, partBytes } = pkg;
@@ -337,8 +338,9 @@ export function parseWorkbookSheets(xml) {
337
338
  name: attrs.name ?? '',
338
339
  relId: attrs['r:id'] ?? '',
339
340
  };
340
- if (attrs.state === 'hidden' || attrs.state === 'veryHidden')
341
- entry.state = attrs.state;
341
+ const state = enumToken(attrs.state, isVisibility);
342
+ if (state !== undefined && state !== 'visible')
343
+ entry.state = state;
342
344
  sheets.push(entry);
343
345
  }
344
346
  return sheets;
@@ -386,9 +388,9 @@ export function applyWorkbookView(view, xml) {
386
388
  const activeTab = numInteger(attrs.activeTab, 0);
387
389
  if (activeTab !== undefined)
388
390
  view.activeTab = activeTab;
389
- if (attrs.visibility === 'hidden' || attrs.visibility === 'veryHidden') {
390
- view.visibility = attrs.visibility;
391
- }
391
+ const visibility = enumToken(attrs.visibility, isVisibility);
392
+ if (visibility !== undefined && visibility !== 'visible')
393
+ view.visibility = visibility;
392
394
  if (boolStrict(attrs.minimized))
393
395
  view.minimized = true;
394
396
  return;
@@ -439,57 +441,25 @@ const CORE_PROPERTY_LOCAL_NAMES = new Set([
439
441
  'modified',
440
442
  ]);
441
443
  function applyCoreProperties(workbook, xml) {
442
- let capture = '';
443
- let text = '';
444
- parseXml(xml, {
445
- onOpen(name) {
446
- const local = localName(name);
447
- capture = CORE_PROPERTY_LOCAL_NAMES.has(local) ? local : '';
448
- text = '';
449
- },
450
- onText(chunk) {
451
- if (capture !== '')
452
- text += chunk;
453
- },
454
- onClose(name) {
455
- if (capture === '' || localName(name) !== capture)
456
- return;
457
- if (capture === 'title')
458
- workbook.properties.title = text;
459
- else if (capture === 'creator')
460
- workbook.properties.creator = text;
461
- else if (capture === 'lastModifiedBy')
462
- workbook.properties.lastModifiedBy = text;
463
- else {
464
- const date = new Date(text);
465
- if (!Number.isNaN(date.getTime())) {
466
- if (capture === 'created')
467
- workbook.properties.created = date;
468
- else
469
- workbook.properties.modified = date;
470
- }
444
+ for (const { local, text } of capturedText(xml, CORE_PROPERTY_LOCAL_NAMES)) {
445
+ if (local === 'title')
446
+ workbook.properties.title = text;
447
+ else if (local === 'creator')
448
+ workbook.properties.creator = text;
449
+ else if (local === 'lastModifiedBy')
450
+ workbook.properties.lastModifiedBy = text;
451
+ else {
452
+ const date = new Date(text);
453
+ if (!Number.isNaN(date.getTime())) {
454
+ if (local === 'created')
455
+ workbook.properties.created = date;
456
+ else
457
+ workbook.properties.modified = date;
471
458
  }
472
- capture = '';
473
- },
474
- });
459
+ }
460
+ }
475
461
  }
476
462
  function applyAppProperties(workbook, xml) {
477
- let capture = false;
478
- let text = '';
479
- parseXml(xml, {
480
- onOpen(name) {
481
- capture = localName(name) === 'Company';
482
- text = '';
483
- },
484
- onText(chunk) {
485
- if (capture)
486
- text += chunk;
487
- },
488
- onClose(name) {
489
- if (!capture || localName(name) !== 'Company')
490
- return;
491
- workbook.properties.company = text;
492
- capture = false;
493
- },
494
- });
463
+ for (const { text } of capturedText(xml, 'Company'))
464
+ workbook.properties.company = text;
495
465
  }
@@ -1,13 +1,47 @@
1
1
  import type { RichTextRun } from '../../core/value.ts';
2
- import type { XmlAttributes } from '../../xml/xml-read.ts';
2
+ import { type XmlAttributes } from '../../xml/xml-read.ts';
3
+ /**
4
+ * What {@link RunAccumulator.close} did with an element: `'container'` means the `<si>`/`<is>` itself
5
+ * closed and the caller should commit whatever it makes of the gathered runs, the one step the two
6
+ * readers do differently; `'claimed'` means the machine handled it; `'other'` leaves it to the caller.
7
+ *
8
+ * Three values rather than a boolean because both callers need to tell "the machine dealt with it"
9
+ * from "your string is complete", and a boolean would mean something different to each of them.
10
+ */
11
+ export type RunClose = 'claimed' | 'container' | 'other';
3
12
  export declare class RunAccumulator {
4
13
  #private;
5
- beginContainer(): void;
14
+ /**
15
+ * @param options.container the element that opens one string: `'si'` for the shared-string pool,
16
+ * `'is'` for an inline string in a worksheet body.
17
+ * @param options.readRuns whether `<r>`/`<rPr>` open a rich-text run. The buffered readers read
18
+ * them; the row stream deliberately does not, and with runs off every `<t>` falls through to
19
+ * {@link plainText}, which is exactly the documented flattening.
20
+ */
21
+ constructor(options: {
22
+ readonly container: 'si' | 'is';
23
+ readonly readRuns: boolean;
24
+ });
6
25
  /** The runs gathered so far. */
7
26
  get runs(): RichTextRun[];
8
- beginRun(): void;
9
- beginProperties(): void;
10
- applyProperty(local: string, attrs: XmlAttributes): void;
11
- appendText(text: string): boolean;
12
- endRun(): void;
27
+ /** Whether the container held at least one `<r>`: what decides rich text from a plain string. */
28
+ get isRich(): boolean;
29
+ /** The container's own text: every `<t>` no run claimed, concatenated and already unescaped. */
30
+ get plainText(): string;
31
+ /**
32
+ * Open a string container by discarding whatever the last one gathered. Called for the machine's
33
+ * own container automatically; a caller whose own element may *hold* one (a `<c>` around an
34
+ * `<is>`) calls it too, or that container inherits the previous one's runs, which is the one way
35
+ * this accumulator can be misused.
36
+ *
37
+ * A new array is installed rather than the existing one emptied, so a value already built from the
38
+ * last container's runs keeps its own array.
39
+ */
40
+ beginContainer(): void;
41
+ /** Drive one element open, and return whether it was one of this machine's own. */
42
+ open(local: string, attrs: XmlAttributes, selfClosing: boolean): boolean;
43
+ /** Feed one run of character data. Ignored unless a `<t>` is open. */
44
+ text(chunk: string): void;
45
+ /** Drive one element close. See {@link RunClose}. */
46
+ close(local: string): RunClose;
13
47
  }
@@ -1,43 +1,107 @@
1
+ import { decodeSpreadsheetText, TextCapture } from '../../xml/xml-read.js';
1
2
  import { applyFontChild } from './read-styles.js';
2
3
  export class RunAccumulator {
4
+ #container;
5
+ #readRuns;
6
+ #capture = new TextCapture('t');
3
7
  #runs = [];
4
8
  #font = null;
5
- #text = '';
9
+ #inProperties = false;
10
+ #runText = '';
11
+ #plain = '';
6
12
  #inRun = false;
7
- beginContainer() {
8
- this.#runs = [];
9
- this.#font = null;
10
- this.#inRun = false;
13
+ #isRich = false;
14
+ #inContainer = false;
15
+ constructor(options) {
16
+ this.#container = options.container;
17
+ this.#readRuns = options.readRuns;
11
18
  }
12
19
  get runs() {
13
20
  return this.#runs;
14
21
  }
15
- beginRun() {
16
- this.#inRun = true;
22
+ get isRich() {
23
+ return this.#isRich;
24
+ }
25
+ get plainText() {
26
+ return this.#plain;
27
+ }
28
+ beginContainer() {
29
+ this.#runs = [];
17
30
  this.#font = null;
18
- this.#text = '';
19
- }
20
- beginProperties() {
21
- if (this.#inRun)
22
- this.#font = {};
23
- }
24
- applyProperty(local, attrs) {
25
- if (this.#font !== null)
26
- applyFontChild(this.#font, local, attrs);
27
- }
28
- appendText(text) {
29
- if (!this.#inRun)
30
- return false;
31
- this.#text += text;
32
- return true;
33
- }
34
- endRun() {
35
- if (!this.#inRun)
36
- return;
37
- const run = { text: this.#text };
38
- if (this.#font !== null && Object.keys(this.#font).length > 0)
39
- run.font = this.#font;
40
- this.#runs.push(run);
31
+ this.#inProperties = false;
32
+ this.#runText = '';
33
+ this.#plain = '';
41
34
  this.#inRun = false;
35
+ this.#isRich = false;
36
+ }
37
+ open(local, attrs, selfClosing) {
38
+ switch (local) {
39
+ case this.#container:
40
+ this.#inContainer = true;
41
+ this.beginContainer();
42
+ return true;
43
+ case 'r':
44
+ if (!this.#readRuns || !this.#inContainer)
45
+ return false;
46
+ this.#isRich = true;
47
+ this.#inRun = true;
48
+ this.#font = null;
49
+ this.#inProperties = false;
50
+ this.#runText = '';
51
+ return true;
52
+ case 'rPr':
53
+ if (!this.#readRuns || !this.#inRun)
54
+ return false;
55
+ this.#font = {};
56
+ this.#inProperties = true;
57
+ return true;
58
+ case 't':
59
+ this.#capture.open(local, selfClosing);
60
+ return true;
61
+ default:
62
+ if (!this.#inProperties || this.#font === null)
63
+ return false;
64
+ applyFontChild(this.#font, local, attrs);
65
+ return true;
66
+ }
67
+ }
68
+ text(chunk) {
69
+ this.#capture.text(chunk);
70
+ }
71
+ close(local) {
72
+ switch (local) {
73
+ case 't': {
74
+ const text = this.#capture.close(local);
75
+ if (text !== undefined) {
76
+ const decoded = decodeSpreadsheetText(text);
77
+ if (this.#inRun)
78
+ this.#runText += decoded;
79
+ else if (this.#inContainer)
80
+ this.#plain += decoded;
81
+ }
82
+ return 'claimed';
83
+ }
84
+ case 'rPr':
85
+ if (!this.#readRuns || !this.#inProperties)
86
+ return 'other';
87
+ this.#inProperties = false;
88
+ return 'claimed';
89
+ case 'r': {
90
+ if (!this.#readRuns || !this.#inRun)
91
+ return 'other';
92
+ this.#inProperties = false;
93
+ const run = { text: this.#runText };
94
+ if (this.#font !== null && Object.keys(this.#font).length > 0)
95
+ run.font = this.#font;
96
+ this.#runs.push(run);
97
+ this.#inRun = false;
98
+ return 'claimed';
99
+ }
100
+ case this.#container:
101
+ this.#inContainer = false;
102
+ return 'container';
103
+ default:
104
+ return 'other';
105
+ }
42
106
  }
43
107
  }
@@ -1,5 +1,5 @@
1
1
  import type { AutoFilter } from '../../core/autofilter.ts';
2
- import type { HeaderFooter, PageBreak, PageMargins, PageSetup, PrintOptions } from '../../core/page-setup.ts';
2
+ import { type HeaderFooter, type PageBreak, type PageMargins, type PageSetup, type PrintOptions } from '../../core/page-setup.ts';
3
3
  import { type SheetProtection } from '../../core/protection.ts';
4
4
  import type { SheetView, Worksheet } from '../../core/worksheet.ts';
5
5
  export declare function sheetViewsXml(view: SheetView, active: boolean): string;
@@ -1,6 +1,7 @@
1
1
  import { encodeAddress } from '../../core/address.js';
2
+ import { isPageOrder, isPageOrientation, } from '../../core/page-setup.js';
2
3
  import { SHEET_PROTECTION_FLAGS } from '../../core/protection.js';
3
- import { attr, boolAttr, escapeAttr, escapeSpreadsheetText, numberText } from '../../xml/xml.js';
4
+ import { boolAttr, checkedToken, escapeAttr, escapeSpreadsheetText, numAttr, numberText, } from '../../xml/xml.js';
4
5
  import { colorAttrs } from './color-xml.js';
5
6
  export function sheetViewsXml(view, active) {
6
7
  const selected = active ? ' tabSelected="1"' : '';
@@ -127,12 +128,16 @@ export function pageMarginsXml(margins) {
127
128
  return `<pageMargins ${attrs}/>`;
128
129
  }
129
130
  export function pageSetupXml(pageSetup, printerSettingsRelId) {
130
- const attrs = attr('paperSize', pageSetup.paperSize) +
131
- attr('scale', pageSetup.scale) +
132
- attr('fitToWidth', pageSetup.fitToWidth) +
133
- attr('fitToHeight', pageSetup.fitToHeight) +
134
- (pageSetup.pageOrder !== undefined ? ` pageOrder="${pageSetup.pageOrder}"` : '') +
135
- (pageSetup.orientation !== undefined ? ` orientation="${pageSetup.orientation}"` : '') +
131
+ const attrs = numAttr('paperSize', pageSetup.paperSize) +
132
+ numAttr('scale', pageSetup.scale) +
133
+ numAttr('fitToWidth', pageSetup.fitToWidth) +
134
+ numAttr('fitToHeight', pageSetup.fitToHeight) +
135
+ (pageSetup.pageOrder === undefined
136
+ ? ''
137
+ : ` pageOrder="${checkedToken(pageSetup.pageOrder, isPageOrder, 'page order')}"`) +
138
+ (pageSetup.orientation === undefined
139
+ ? ''
140
+ : ` orientation="${checkedToken(pageSetup.orientation, isPageOrientation, 'page orientation')}"`) +
136
141
  (printerSettingsRelId !== null ? ` r:id="${printerSettingsRelId}"` : '');
137
142
  return attrs === '' ? '' : `<pageSetup${attrs}/>`;
138
143
  }
@@ -141,8 +146,7 @@ export function pageBreaksXml(breaks, element) {
141
146
  return '';
142
147
  const brks = breaks
143
148
  .map((brk) => {
144
- const maxAttr = brk.max !== undefined ? ` max="${brk.max}"` : '';
145
- return `<brk id="${brk.id}"${maxAttr} man="1"/>`;
149
+ return `<brk${numAttr('id', brk.id)}${numAttr('max', brk.max)} man="1"/>`;
146
150
  })
147
151
  .join('');
148
152
  return `<${element} count="${breaks.length}" manualBreakCount="${breaks.length}">${brks}</${element}>`;
@@ -1,18 +1,6 @@
1
- import { type Alignment, type Border, type DifferentialStyle, type Fill, type Font, type NamedCellStyle, type Protection, type TableStyleTable } from '../../core/style.ts';
1
+ import { type DifferentialStyle, type Font, type NamedCellStyle, type TableStyleTable } from '../../core/style.ts';
2
2
  import { type TableStyle } from '../../core/table-style.ts';
3
- /** A cell's style facets as the writer composes them: cell overrides atop row/column defaults. */
4
- export interface CellStyle {
5
- readonly fill?: Fill | undefined;
6
- readonly numFmt?: string | undefined;
7
- readonly font?: Font | undefined;
8
- readonly border?: Border | undefined;
9
- readonly alignment?: Alignment | undefined;
10
- readonly protection?: Protection | undefined;
11
- /** The quote-prefix flag: an attribute on the xf, not a shared sub-table entry. */
12
- readonly quotePrefix?: boolean | undefined;
13
- /** The `xfId` link into `cellStyleXfs`: the named cell style this format inherits from (0 = Normal). */
14
- readonly xfId?: number | undefined;
15
- }
3
+ import type { XfStyle } from '../style/xf-style.ts';
16
4
  /** What a {@link StyleRegistry} needs from its workbook before any style is interned. */
17
5
  export interface StyleRegistryOptions {
18
6
  /**
@@ -41,7 +29,7 @@ export declare class StyleRegistry {
41
29
  * The `<cellXfs>` index for a composed cell/row/column style. A style with no facet needs
42
30
  * no entry and resolves to the default xf 0, so its owner emits no `s` attribute at all.
43
31
  */
44
- styleId(style: CellStyle): number;
32
+ styleId(style: XfStyle): number;
45
33
  /**
46
34
  * Seed the named cell styles (`<cellStyleXfs>`/`<cellStyles>`) read from a file, in place of the
47
35
  * lone default, interning each style's facets into the shared sub-tables so its `fillId`/`fontId`/…