@shbernal/ts-xlsx 3.0.0 → 3.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 (213) hide show
  1. package/README.md +4 -1
  2. package/dist/bytes.d.ts +7 -0
  3. package/dist/bytes.js +22 -0
  4. package/dist/core/address.d.ts +60 -2
  5. package/dist/core/address.js +40 -24
  6. package/dist/core/autofilter.d.ts +4 -3
  7. package/dist/core/autofilter.js +31 -30
  8. package/dist/core/axis-handle.d.ts +2 -0
  9. package/dist/core/axis-handle.js +5 -2
  10. package/dist/core/cell.d.ts +4 -3
  11. package/dist/core/cell.js +4 -6
  12. package/dist/core/clone.d.ts +29 -0
  13. package/dist/core/clone.js +24 -0
  14. package/dist/core/color-resolution.js +2 -4
  15. package/dist/core/column.d.ts +1 -0
  16. package/dist/core/column.js +3 -0
  17. package/dist/core/comment-thread.js +2 -1
  18. package/dist/core/conditional-formatting-overlay.d.ts +2 -1
  19. package/dist/core/conditional-formatting-overlay.js +2 -2
  20. package/dist/core/conditional-formatting.d.ts +9 -1
  21. package/dist/core/conditional-formatting.js +34 -18
  22. package/dist/core/containers.d.ts +12 -0
  23. package/dist/core/containers.js +5 -0
  24. package/dist/core/data-validation-overlay.d.ts +2 -1
  25. package/dist/core/data-validation-overlay.js +4 -4
  26. package/dist/core/data-validation.d.ts +6 -0
  27. package/dist/core/data-validation.js +15 -4
  28. package/dist/core/date-format.d.ts +20 -0
  29. package/dist/core/date-format.js +160 -0
  30. package/dist/core/date.d.ts +43 -8
  31. package/dist/core/date.js +18 -2
  32. package/dist/core/formula.d.ts +26 -0
  33. package/dist/core/formula.js +20 -4
  34. package/dist/core/grid-edits.d.ts +2 -3
  35. package/dist/core/grid-edits.js +69 -70
  36. package/dist/core/grid-shift.d.ts +58 -9
  37. package/dist/core/grid-shift.js +26 -4
  38. package/dist/core/image.d.ts +13 -9
  39. package/dist/core/image.js +7 -5
  40. package/dist/core/internal.d.ts +8 -2
  41. package/dist/core/limits.d.ts +23 -0
  42. package/dist/core/limits.js +4 -0
  43. package/dist/core/merge.d.ts +5 -4
  44. package/dist/core/merge.js +18 -19
  45. package/dist/core/pivot-table.js +63 -45
  46. package/dist/core/protection.js +2 -11
  47. package/dist/core/range.js +34 -30
  48. package/dist/core/row-input.js +2 -2
  49. package/dist/core/row.d.ts +1 -0
  50. package/dist/core/row.js +3 -0
  51. package/dist/core/style.d.ts +85 -70
  52. package/dist/core/style.js +92 -28
  53. package/dist/core/table-style.d.ts +1 -1
  54. package/dist/core/table-style.js +4 -4
  55. package/dist/core/table.d.ts +27 -9
  56. package/dist/core/table.js +51 -34
  57. package/dist/core/theme.js +6 -5
  58. package/dist/core/value.d.ts +9 -0
  59. package/dist/core/value.js +36 -34
  60. package/dist/core/workbook-media.d.ts +34 -0
  61. package/dist/core/workbook-media.js +44 -0
  62. package/dist/core/workbook-styles.d.ts +67 -1
  63. package/dist/core/workbook-vba.js +3 -2
  64. package/dist/core/workbook.d.ts +23 -2
  65. package/dist/core/workbook.js +24 -40
  66. package/dist/core/worksheet-comments.d.ts +2 -1
  67. package/dist/core/worksheet-comments.js +20 -13
  68. package/dist/core/worksheet-merges.d.ts +44 -0
  69. package/dist/core/worksheet-merges.js +59 -0
  70. package/dist/core/worksheet-model.d.ts +9 -1
  71. package/dist/core/worksheet-model.js +24 -9
  72. package/dist/core/worksheet.d.ts +55 -6
  73. package/dist/core/worksheet.js +36 -44
  74. package/dist/customui/ribbon.js +2 -1
  75. package/dist/entries/core.d.ts +18 -13
  76. package/dist/entries/core.js +12 -6
  77. package/dist/entries/xlsx.d.ts +1 -1
  78. package/dist/errors.d.ts +64 -0
  79. package/dist/errors.js +22 -0
  80. package/dist/hex.d.ts +8 -0
  81. package/dist/hex.js +3 -0
  82. package/dist/io/csv/delimiter.d.ts +9 -0
  83. package/dist/io/csv/delimiter.js +6 -0
  84. package/dist/io/csv/read.js +11 -4
  85. package/dist/io/csv/write.d.ts +9 -2
  86. package/dist/io/csv/write.js +9 -38
  87. package/dist/io/opc/inflate.js +14 -0
  88. package/dist/io/opc/namespaces.d.ts +16 -0
  89. package/dist/io/opc/namespaces.js +4 -0
  90. package/dist/io/opc/part-paths.d.ts +9 -0
  91. package/dist/io/opc/part-paths.js +1 -1
  92. package/dist/io/opc/read-opc.d.ts +54 -14
  93. package/dist/io/opc/read-opc.js +42 -20
  94. package/dist/io/opc/read-options.d.ts +5 -1
  95. package/dist/io/opc/sniff-format.d.ts +3 -3
  96. package/dist/io/opc/sniff-format.js +2 -2
  97. package/dist/io/style/xf-style.d.ts +23 -1
  98. package/dist/io/style/xf-style.js +8 -0
  99. package/dist/io/xlsb/formula.d.ts +2 -2
  100. package/dist/io/xlsb/formula.js +49 -34
  101. package/dist/io/xlsb/primitives.js +8 -14
  102. package/dist/io/xlsb/ptg-functions.d.ts +19 -10
  103. package/dist/io/xlsb/ptg-functions.js +385 -596
  104. package/dist/io/xlsb/read-styles.js +45 -81
  105. package/dist/io/xlsb/read-worksheet.d.ts +20 -1
  106. package/dist/io/xlsb/read-worksheet.js +73 -89
  107. package/dist/io/xlsb/read.d.ts +6 -3
  108. package/dist/io/xlsb/read.js +44 -23
  109. package/dist/io/xlsb/record-stream.d.ts +30 -0
  110. package/dist/io/xlsb/record-stream.js +20 -0
  111. package/dist/io/xlsb/record-types.d.ts +1 -5
  112. package/dist/io/xlsb/record-types.js +1 -5
  113. package/dist/io/xlsx/cell-accumulator.d.ts +8 -1
  114. package/dist/io/xlsx/cell-accumulator.js +32 -9
  115. package/dist/io/xlsx/cell-style-resolution.d.ts +25 -0
  116. package/dist/io/xlsx/cell-style-resolution.js +29 -0
  117. package/dist/io/xlsx/cell-value.d.ts +5 -3
  118. package/dist/io/xlsx/cell-value.js +13 -15
  119. package/dist/io/xlsx/color-xml.js +3 -2
  120. package/dist/io/xlsx/column-budget.d.ts +26 -0
  121. package/dist/io/xlsx/column-budget.js +22 -0
  122. package/dist/io/xlsx/comments.d.ts +6 -2
  123. package/dist/io/xlsx/comments.js +36 -32
  124. package/dist/io/xlsx/conditional-formatting.d.ts +6 -3
  125. package/dist/io/xlsx/conditional-formatting.js +30 -26
  126. package/dist/io/xlsx/data-validation.js +29 -27
  127. package/dist/io/xlsx/edit-vba.d.ts +7 -2
  128. package/dist/io/xlsx/edit-vba.js +14 -21
  129. package/dist/io/xlsx/font-xml.d.ts +7 -0
  130. package/dist/io/xlsx/font-xml.js +104 -0
  131. package/dist/io/xlsx/hyperlinks.d.ts +37 -5
  132. package/dist/io/xlsx/hyperlinks.js +22 -13
  133. package/dist/io/xlsx/images.js +11 -13
  134. package/dist/io/xlsx/namespaces.d.ts +16 -0
  135. package/dist/io/xlsx/namespaces.js +7 -0
  136. package/dist/io/xlsx/package-plan.d.ts +14 -2
  137. package/dist/io/xlsx/package-plan.js +39 -11
  138. package/dist/io/xlsx/pivot.js +8 -7
  139. package/dist/io/xlsx/read-parts.d.ts +59 -0
  140. package/dist/io/xlsx/read-parts.js +252 -0
  141. package/dist/io/xlsx/read-pivot.js +2 -1
  142. package/dist/io/xlsx/read-repair.d.ts +26 -0
  143. package/dist/io/xlsx/read-repair.js +39 -0
  144. package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +6 -3
  145. package/dist/io/xlsx/read-rows.d.ts +18 -5
  146. package/dist/io/xlsx/read-rows.js +45 -31
  147. package/dist/io/xlsx/read-shared-strings.js +3 -2
  148. package/dist/io/xlsx/read-styles.d.ts +1 -6
  149. package/dist/io/xlsx/read-styles.js +6 -71
  150. package/dist/io/xlsx/read-workbook-xml.d.ts +36 -0
  151. package/dist/io/xlsx/read-workbook-xml.js +170 -0
  152. package/dist/io/xlsx/read-worksheet.d.ts +2 -1
  153. package/dist/io/xlsx/read-worksheet.js +35 -164
  154. package/dist/io/xlsx/read.d.ts +5 -12
  155. package/dist/io/xlsx/read.js +73 -406
  156. package/dist/io/xlsx/rich-text.js +1 -1
  157. package/dist/io/xlsx/row-position.d.ts +18 -0
  158. package/dist/io/xlsx/row-position.js +11 -0
  159. package/dist/io/xlsx/row-xml.d.ts +128 -0
  160. package/dist/io/xlsx/row-xml.js +203 -0
  161. package/dist/io/xlsx/shared-formulas.js +2 -2
  162. package/dist/io/xlsx/sheet-properties.d.ts +10 -1
  163. package/dist/io/xlsx/sheet-properties.js +145 -9
  164. package/dist/io/xlsx/style-elements.d.ts +43 -0
  165. package/dist/io/xlsx/style-elements.js +156 -0
  166. package/dist/io/xlsx/styles.d.ts +12 -3
  167. package/dist/io/xlsx/styles.js +5 -207
  168. package/dist/io/xlsx/tables.js +10 -14
  169. package/dist/io/xlsx/theme-xml.d.ts +26 -4
  170. package/dist/io/xlsx/theme-xml.js +107 -69
  171. package/dist/io/xlsx/threaded-comments.d.ts +8 -10
  172. package/dist/io/xlsx/threaded-comments.js +2 -1
  173. package/dist/io/xlsx/workbook-xml.d.ts +54 -4
  174. package/dist/io/xlsx/workbook-xml.js +60 -34
  175. package/dist/io/xlsx/worksheet-xml.d.ts +23 -70
  176. package/dist/io/xlsx/worksheet-xml.js +48 -229
  177. package/dist/io/xlsx/write-stream.d.ts +65 -16
  178. package/dist/io/xlsx/write-stream.js +50 -20
  179. package/dist/io/xlsx/write.d.ts +1 -2
  180. package/dist/io/xlsx/write.js +114 -74
  181. package/dist/rel-type.d.ts +16 -0
  182. package/dist/rel-type.js +6 -0
  183. package/dist/token-set.d.ts +13 -0
  184. package/dist/token-set.js +4 -1
  185. package/dist/vba/bytes.d.ts +14 -5
  186. package/dist/vba/bytes.js +16 -6
  187. package/dist/vba/cfb-format.d.ts +8 -0
  188. package/dist/vba/cfb-format.js +1 -0
  189. package/dist/vba/cfb-writer.d.ts +9 -0
  190. package/dist/vba/cfb-writer.js +12 -9
  191. package/dist/vba/cfb.d.ts +13 -1
  192. package/dist/vba/cfb.js +73 -51
  193. package/dist/vba/codepage.js +2 -1
  194. package/dist/vba/errors.d.ts +7 -0
  195. package/dist/vba/ms-ovba.js +51 -16
  196. package/dist/vba/project-editor.js +35 -40
  197. package/dist/vba/project.d.ts +11 -1
  198. package/dist/vba/project.js +27 -8
  199. package/dist/vba/vba-encoding.js +4 -5
  200. package/dist/xml/xml-attrs.d.ts +37 -0
  201. package/dist/xml/xml-attrs.js +30 -0
  202. package/dist/xml/xml-chars.d.ts +40 -0
  203. package/dist/xml/xml-chars.js +12 -0
  204. package/dist/xml/xml-namespaces.d.ts +31 -0
  205. package/dist/xml/xml-namespaces.js +50 -0
  206. package/dist/xml/xml-read.d.ts +72 -10
  207. package/dist/xml/xml-read.js +94 -18
  208. package/dist/xml/xml-scan.d.ts +15 -37
  209. package/dist/xml/xml-scan.js +12 -40
  210. package/dist/xml/xml.d.ts +28 -27
  211. package/dist/xml/xml.js +24 -24
  212. package/package.json +12 -7
  213. /package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +0 -0
@@ -1,42 +1,50 @@
1
- import { MAX_COLUMN, MAX_ROW } from '../../core/address.js';
2
- import { AuthoringError } from '../../errors.js';
3
- import { closeEmptyElements } from '../../xml/xml-read.js';
4
- import { boolStrict, localName, numInteger, xmlEvents } from '../../xml/xml-scan.js';
1
+ import { Workbook } from '../../core/workbook.js';
2
+ import { AuthoringError, quoted } from '../../errors.js';
3
+ import { closeEmptyElements, parseXmlPasses } from '../../xml/xml-read.js';
4
+ import { boolStrict, localName, xmlEvents } from '../../xml/xml-scan.js';
5
5
  import { openSpreadsheetPackage, readPartRelationships } from '../opc/read-opc.js';
6
6
  import { unsupportedWorkbookPart } from '../opc/sniff-format.js';
7
7
  import { CellAccumulator } from './cell-accumulator.js';
8
+ import { CellStyleResolver } from './cell-style-resolution.js';
9
+ import { ColumnRecordBudget, takeColumnSpan } from './column-budget.js';
8
10
  import { XlsxParseError } from './errors.js';
11
+ import { SHARED_STRINGS_PART, STYLES_PART } from './part-names.js';
9
12
  import { parseSharedStrings } from './read-shared-strings.js';
10
- import { parseStyleTable, parseWorkbookSheets, } from './read.js';
13
+ import { workbookPropertiesPass, parseStyleTable, workbookSheetsPass, } from './read.js';
14
+ import { RowPositionTracker } from './row-position.js';
11
15
  export function* readSheetRows(data, options = {}) {
12
16
  const pkg = openPackage(data, options.maxUncompressedBytes);
13
17
  const chosen = pickSheet(pkg.sheets, options.sheet);
14
18
  const sheetXml = pkg.sheetXml(chosen.relId);
15
19
  if (sheetXml === undefined)
16
20
  return;
17
- yield* scanSheet(sheetXml, pkg.sharedStrings, pkg.xfStyles, new Set(), []);
21
+ yield* scanSheet(sheetXml, pkg.sharedStrings, pkg.xfStyles, pkg.dateEpoch, new Set(), []);
18
22
  }
19
23
  export function* readWorkbookStream(data, options = {}) {
20
24
  const pkg = openPackage(data, options.maxUncompressedBytes);
21
25
  for (const sheet of pkg.sheets) {
22
26
  const xml = pkg.sheetXml(sheet.relId) ?? '';
23
- yield new StreamedSheetReader(sheet.name, xml, pkg.sharedStrings, pkg.xfStyles);
27
+ yield new StreamedSheetReader(sheet.name, xml, pkg.sharedStrings, pkg.xfStyles, pkg.dateEpoch);
24
28
  }
25
29
  }
26
30
  function openPackage(data, maxUncompressedBytes) {
27
- const { pkg, workbookXml } = openSpreadsheetPackage(data, maxUncompressedBytes);
28
- const { partText: text } = pkg;
31
+ const { pkg, documentPath, workbookXml } = openSpreadsheetPackage(data, maxUncompressedBytes);
32
+ const { partText: text, partBytes } = pkg;
29
33
  if (workbookXml === undefined) {
30
- throw unsupportedWorkbookPart(text, 'the binary .xlsb format (BIFF12) cannot be row-streamed yet; read it with readXlsx or readXlsb');
34
+ throw unsupportedWorkbookPart(partBytes, documentPath, 'the binary .xlsb format (BIFF12) cannot be row-streamed yet; read it with readXlsx or readXlsb');
31
35
  }
32
- const sheets = parseWorkbookSheets(workbookXml);
33
- const rels = readPartRelationships('xl/workbook.xml', text);
34
- const sharedStrings = parseSharedStrings(text('xl/sharedStrings.xml') ?? '');
35
- const { cellXfs: xfStyles } = parseStyleTable(text('xl/styles.xml') ?? '');
36
+ const properties = new Workbook();
37
+ const sheetsPass = workbookSheetsPass();
38
+ parseXmlPasses(workbookXml, [sheetsPass, workbookPropertiesPass(properties)]);
39
+ const sheets = sheetsPass.result();
40
+ const rels = readPartRelationships(documentPath, text);
41
+ const sharedStrings = parseSharedStrings(rels.relatedTextOrPath('sharedStrings', SHARED_STRINGS_PART));
42
+ const { cellXfs: xfStyles } = parseStyleTable(rels.relatedTextOrPath('styles', STYLES_PART));
36
43
  return {
37
44
  sheets,
38
45
  sharedStrings,
39
46
  xfStyles,
47
+ dateEpoch: properties.dateEpoch,
40
48
  sheetXml(relId) {
41
49
  const target = rels.byId(relId)?.target;
42
50
  return target === undefined ? undefined : text(rels.pathOf(target));
@@ -57,7 +65,7 @@ function pickSheet(sheets, selector) {
57
65
  }
58
66
  const sheet = sheets.find((candidate) => candidate.name === selector);
59
67
  if (sheet === undefined)
60
- throw new AuthoringError(`no worksheet named ${JSON.stringify(selector)}`);
68
+ throw new AuthoringError(`no worksheet named ${quoted(selector)}`);
61
69
  return sheet;
62
70
  }
63
71
  class StreamedSheetReader {
@@ -65,20 +73,22 @@ class StreamedSheetReader {
65
73
  #xml;
66
74
  #sharedStrings;
67
75
  #xfStyles;
76
+ #dateEpoch;
68
77
  #hiddenColumns = new Set();
69
78
  #merges = [];
70
79
  #scanned = false;
71
- constructor(name, xml, sharedStrings, xfStyles) {
80
+ constructor(name, xml, sharedStrings, xfStyles, dateEpoch) {
72
81
  this.name = name;
73
82
  this.#xml = xml;
74
83
  this.#sharedStrings = sharedStrings;
75
84
  this.#xfStyles = xfStyles;
85
+ this.#dateEpoch = dateEpoch;
76
86
  }
77
87
  *rows() {
78
88
  this.#hiddenColumns = new Set();
79
89
  this.#merges = [];
80
90
  this.#scanned = false;
81
- yield* scanSheet(this.#xml, this.#sharedStrings, this.#xfStyles, this.#hiddenColumns, this.#merges);
91
+ yield* scanSheet(this.#xml, this.#sharedStrings, this.#xfStyles, this.#dateEpoch, this.#hiddenColumns, this.#merges);
82
92
  this.#scanned = true;
83
93
  }
84
94
  get hiddenColumns() {
@@ -97,17 +107,20 @@ class StreamedSheetReader {
97
107
  }
98
108
  }
99
109
  const CELL_EMPTY_CLOSE = new Set(['c']);
100
- function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
110
+ function* scanSheet(xml, sharedStrings, xfStyles, dateEpoch, hiddenColumns, merges) {
101
111
  let rowNumber = 0;
102
- let lastRow = 0;
103
112
  let rowHidden = false;
104
113
  let rowInGrid = true;
105
114
  let cells = [];
106
- const cell = new CellAccumulator({ richRuns: false });
115
+ const columnBudget = new ColumnRecordBudget();
116
+ const styleResolution = new CellStyleResolver();
117
+ const rowPosition = new RowPositionTracker();
118
+ const cell = new CellAccumulator({ richRuns: false, dateEpoch });
107
119
  const finalizeCell = () => {
108
120
  if (cell.ref === '' || cell.col < 0 || !rowInGrid)
109
121
  return;
110
- const style = cell.styleIndex >= 0 ? xfStyles[cell.styleIndex] : undefined;
122
+ const styleIndex = styleResolution.indexFor(cell.col, cell.styleIndex);
123
+ const style = styleIndex >= 0 ? xfStyles[styleIndex] : undefined;
111
124
  const value = cell.decode(sharedStrings, style);
112
125
  if (value !== null) {
113
126
  const { col, ref } = cell;
@@ -125,15 +138,15 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
125
138
  continue;
126
139
  switch (local) {
127
140
  case 'row': {
128
- rowNumber = numInteger(event.attrs.r, 1) ?? lastRow + 1;
129
- lastRow = rowNumber;
130
- rowInGrid = rowNumber <= MAX_ROW;
141
+ ({ number: rowNumber, inGrid: rowInGrid } = rowPosition.open(event.attrs));
131
142
  rowHidden = boolStrict(event.attrs.hidden);
143
+ cell.openRow(rowInGrid ? rowNumber : -1);
144
+ styleResolution.openRow(event.attrs);
132
145
  cells = [];
133
146
  break;
134
147
  }
135
148
  case 'col':
136
- collectHiddenColumn(event.attrs, hiddenColumns);
149
+ collectColumn(event.attrs, hiddenColumns, styleResolution, columnBudget);
137
150
  break;
138
151
  case 'mergeCell':
139
152
  if (event.attrs.ref !== undefined)
@@ -149,19 +162,20 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
149
162
  if (claimed === 'cell')
150
163
  finalizeCell();
151
164
  else if (claimed === 'other' && local === 'row') {
165
+ styleResolution.closeRow();
152
166
  if (rowInGrid)
153
167
  yield { number: rowNumber, hidden: rowHidden, cells };
154
168
  }
155
169
  }
156
170
  }
157
- function collectHiddenColumn(attrs, hiddenColumns) {
158
- if (!boolStrict(attrs.hidden))
171
+ function collectColumn(attrs, hiddenColumns, styleResolution, budget) {
172
+ const span = takeColumnSpan(attrs, budget);
173
+ if (span === undefined)
159
174
  return;
160
- const min = numInteger(attrs.min, 1);
161
- const max = numInteger(attrs.max, 1);
162
- if (min === undefined || max === undefined)
175
+ const { first: min, last } = span;
176
+ styleResolution.noteColumnSpan(min, last, attrs);
177
+ if (!boolStrict(attrs.hidden))
163
178
  return;
164
- const last = Math.min(max, MAX_COLUMN);
165
179
  for (let index = min; index <= last; index++)
166
180
  hiddenColumns.add(index);
167
181
  }
@@ -1,6 +1,7 @@
1
1
  import { parseXml } from '../../xml/xml-read.js';
2
2
  import { localName } from '../../xml/xml-scan.js';
3
- import { RunAccumulator } from './rich-runs.js';
3
+ import { RunAccumulator } from './read-rich-runs.js';
4
+ const SHARED_STRING_EMPTY_CLOSES = new Set(['si']);
4
5
  export function parseSharedStrings(xml) {
5
6
  if (xml === '')
6
7
  return [];
@@ -18,6 +19,6 @@ export function parseSharedStrings(xml) {
18
19
  return;
19
20
  strings.push(runs.isRich ? { richText: runs.runs } : runs.plainText);
20
21
  },
21
- });
22
+ }, { closeEmptyElements: SHARED_STRING_EMPTY_CLOSES });
22
23
  return strings;
23
24
  }
@@ -1,11 +1,6 @@
1
- import { type Font, type TableStyleTable } from '../../core/style.ts';
2
- import { type XmlAttributes } from '../../xml/xml-scan.ts';
1
+ import type { TableStyleTable } from '../../core/workbook-styles.ts';
3
2
  import { type StyleTable } from '../style/xf-style.ts';
4
- export type FontDraft = {
5
- -readonly [K in keyof Font]?: Font[K];
6
- };
7
3
  export declare function parseStyleTable(xml: string): StyleTable;
8
- export declare function applyFontChild(draft: FontDraft, local: string, attrs: XmlAttributes): void;
9
4
  /**
10
5
  * Extract the custom indexed-color palette (`<colors><indexedColors>`) from styles.xml as verbatim
11
6
  * `<rgbColor rgb="…"/>` fragments, or an empty list when the file rides the default palette. Kept raw
@@ -1,8 +1,10 @@
1
- import { ALIGNMENT_FACETS, isBorderStyle, isFillPatternType, isFontScheme, isFontVerticalAlignment, isNamedUnderlineStyle, } from '../../core/style.js';
1
+ import { ALIGNMENT_FACETS, isBorderStyle, isFillPatternType, } from '../../core/style.js';
2
+ import { numFinite, numInteger } from '../../xml/xml-attrs.js';
2
3
  import { closeEmptyElements, elementSubtrees, openElements, } from '../../xml/xml-read.js';
3
- import { boolPresent, boolStrict, boolTristate, localName, numFinite, numInteger, xmlEvents, } from '../../xml/xml-scan.js';
4
- import { NO_PRESERVED_STYLE_TABLES, numFmtCodeFor, resolveStyleTable, } from '../style/xf-style.js';
4
+ import { boolStrict, boolTristate, localName, xmlEvents, } from '../../xml/xml-scan.js';
5
+ import { NO_PRESERVED_STYLE_TABLES, numFmtCodeFor, protectionFrom, resolveStyleTable, } from '../style/xf-style.js';
5
6
  import { parseColor } from './color-xml.js';
7
+ import { applyFontChild } from './font-xml.js';
6
8
  const BORDER_EDGE_NAMES = ['left', 'right', 'top', 'bottom', 'diagonal'];
7
9
  const BORDER_EDGES = new Set(BORDER_EDGE_NAMES);
8
10
  const isBorderEdgeName = (name) => BORDER_EDGES.has(name);
@@ -309,68 +311,6 @@ function parseCellStyles(events) {
309
311
  }
310
312
  return names;
311
313
  }
312
- export function applyFontChild(draft, local, attrs) {
313
- switch (local) {
314
- case 'b':
315
- draft.bold = boolPresent(attrs.val);
316
- break;
317
- case 'i':
318
- draft.italic = boolPresent(attrs.val);
319
- break;
320
- case 'strike':
321
- draft.strike = boolPresent(attrs.val);
322
- break;
323
- case 'outline':
324
- draft.outline = boolPresent(attrs.val);
325
- break;
326
- case 'u':
327
- draft.underline =
328
- attrs.val === undefined
329
- ? true
330
- : attrs.val === 'none'
331
- ? false
332
- : isNamedUnderlineStyle(attrs.val)
333
- ? attrs.val
334
- : true;
335
- break;
336
- case 'vertAlign':
337
- if (attrs.val !== undefined && isFontVerticalAlignment(attrs.val))
338
- draft.vertAlign = attrs.val;
339
- break;
340
- case 'sz': {
341
- const size = numFinite(attrs.val);
342
- if (size !== undefined)
343
- draft.size = size;
344
- break;
345
- }
346
- case 'color':
347
- draft.color = parseColor(attrs);
348
- break;
349
- case 'name':
350
- case 'rFont':
351
- if (attrs.val !== undefined)
352
- draft.name = attrs.val;
353
- break;
354
- case 'family': {
355
- const family = numInteger(attrs.val);
356
- if (family !== undefined)
357
- draft.family = family;
358
- break;
359
- }
360
- case 'charset': {
361
- const charset = numInteger(attrs.val);
362
- if (charset !== undefined)
363
- draft.charset = charset;
364
- break;
365
- }
366
- case 'scheme':
367
- if (attrs.val !== undefined && isFontScheme(attrs.val))
368
- draft.scheme = attrs.val;
369
- break;
370
- default:
371
- break;
372
- }
373
- }
374
314
  function resolveNumFmt(raw, custom) {
375
315
  const id = numInteger(raw, 1);
376
316
  return id === undefined ? undefined : numFmtCodeFor(id, custom);
@@ -426,12 +366,7 @@ function assignAlignmentToken(out, key, raw) {
426
366
  out[key] = raw;
427
367
  }
428
368
  function parseProtection(attrs) {
429
- const out = {};
430
- if (boolTristate(attrs.locked) === false)
431
- out.locked = false;
432
- if (boolStrict(attrs.hidden))
433
- out.hidden = true;
434
- return Object.keys(out).length > 0 ? out : undefined;
369
+ return protectionFrom({ locked: boolTristate(attrs.locked), hidden: boolStrict(attrs.hidden) });
435
370
  }
436
371
  export function parseIndexedColors(stylesXml) {
437
372
  return capturedFragments(stylesXml, 'indexedColors');
@@ -0,0 +1,36 @@
1
+ import { type WorkbookProtection } from '../../core/workbook-protection.ts';
2
+ import type { DefinedName, Workbook, WorkbookView } from '../../core/workbook.ts';
3
+ import { type WorksheetState } from '../../core/worksheet.ts';
4
+ import { type CollectingPass, type SaxPass } from '../../xml/xml-read.ts';
5
+ export interface SheetEntry {
6
+ readonly name: string;
7
+ readonly relId: string;
8
+ readonly state?: WorksheetState['state'];
9
+ }
10
+ export declare function workbookSheetsPass(): CollectingPass<SheetEntry[]>;
11
+ export declare function workbookProtectionPass(): CollectingPass<WorkbookProtection | undefined>;
12
+ /**
13
+ * Apply `<workbookPr>`: the workbook's date system and its VBA code name.
14
+ *
15
+ * Both are read for the same reason and it is not that the model computes anything from them. The
16
+ * date system is what every serial in every sheet counts from, so a workbook read without it is read
17
+ * with every date four years and a day out; the code name is what the VBA project means by
18
+ * `ThisWorkbook`, so a `.xlsm` written back without it has had its macros unbound from its document.
19
+ * Neither has any signal in the file other than this element.
20
+ */
21
+ export declare function workbookPropertiesPass(workbook: Workbook): SaxPass;
22
+ export declare function workbookViewPass(view: WorkbookView): SaxPass;
23
+ export interface DefinedNamesPass extends SaxPass {
24
+ /**
25
+ * The names, scoped against the sheet order.
26
+ *
27
+ * The order is supplied here rather than to the pass, and that is what lets the names ride the same
28
+ * scan as everything else this part carries. A scoped name's `localSheetId` indexes the sheets in
29
+ * declaration order, and the model's answer for index n is known only after the sheet loop has run
30
+ * and repaired the names it had to; resolving during the scan would have forced a second one.
31
+ */
32
+ result(sheetOrder: readonly string[]): DefinedName[];
33
+ }
34
+ export declare function definedNamesPass(): DefinedNamesPass;
35
+ export declare function applyCoreProperties(workbook: Workbook, xml: string): void;
36
+ export declare function applyAppProperties(workbook: Workbook, xml: string): void;
@@ -0,0 +1,170 @@
1
+ import { parseDateText } from '../../core/date.js';
2
+ import { unmangleFunctions } from '../../core/formula.js';
3
+ import { WORKBOOK_PROTECTION_CREDENTIAL_ATTRS, } from '../../core/workbook-protection.js';
4
+ import { isVisibility } from '../../core/worksheet.js';
5
+ import { enumToken, numInteger } from '../../xml/xml-attrs.js';
6
+ import { capturedText, TextCapture } from '../../xml/xml-read.js';
7
+ import { boolStrict, localName } from '../../xml/xml-scan.js';
8
+ import { relAttr } from '../opc/namespaces.js';
9
+ export function workbookSheetsPass() {
10
+ const sheets = [];
11
+ return {
12
+ handlers: {
13
+ onOpen(name, attrs, _selfClosing, scope) {
14
+ if (localName(name) !== 'sheet')
15
+ return;
16
+ const entry = {
17
+ name: attrs.name ?? '',
18
+ relId: relAttr(scope, attrs, 'id') ?? '',
19
+ };
20
+ const state = enumToken(attrs.state, isVisibility);
21
+ if (state !== undefined && state !== 'visible')
22
+ entry.state = state;
23
+ sheets.push(entry);
24
+ },
25
+ },
26
+ result: () => sheets,
27
+ };
28
+ }
29
+ export function workbookProtectionPass() {
30
+ let found;
31
+ const handlers = {
32
+ onOpen(name, attrs) {
33
+ if (localName(name) !== 'workbookProtection')
34
+ return;
35
+ const protection = {};
36
+ if (boolStrict(attrs.lockStructure))
37
+ protection.lockStructure = true;
38
+ if (boolStrict(attrs.lockWindows))
39
+ protection.lockWindows = true;
40
+ if (boolStrict(attrs.lockRevision))
41
+ protection.lockRevision = true;
42
+ const credentials = {};
43
+ for (const key of WORKBOOK_PROTECTION_CREDENTIAL_ATTRS) {
44
+ const value = attrs[key];
45
+ if (value !== undefined)
46
+ credentials[key] = value;
47
+ }
48
+ if (Object.keys(credentials).length > 0)
49
+ protection.credentials = credentials;
50
+ found = protection;
51
+ },
52
+ };
53
+ return { handlers, result: () => found };
54
+ }
55
+ export function workbookPropertiesPass(workbook) {
56
+ let seen = false;
57
+ return {
58
+ handlers: {
59
+ onOpen(name, attrs) {
60
+ if (seen || localName(name) !== 'workbookPr')
61
+ return;
62
+ seen = true;
63
+ if (boolStrict(attrs.date1904))
64
+ workbook.dateEpoch = 1904;
65
+ if (attrs.codeName !== undefined)
66
+ workbook.codeName = attrs.codeName;
67
+ },
68
+ },
69
+ };
70
+ }
71
+ export function workbookViewPass(view) {
72
+ let seen = false;
73
+ return {
74
+ handlers: {
75
+ onOpen(name, attrs) {
76
+ if (seen || localName(name) !== 'workbookView')
77
+ return;
78
+ seen = true;
79
+ const x = numInteger(attrs.xWindow);
80
+ if (x !== undefined)
81
+ view.x = x;
82
+ const y = numInteger(attrs.yWindow);
83
+ if (y !== undefined)
84
+ view.y = y;
85
+ const width = numInteger(attrs.windowWidth, 0);
86
+ if (width !== undefined)
87
+ view.width = width;
88
+ const height = numInteger(attrs.windowHeight, 0);
89
+ if (height !== undefined)
90
+ view.height = height;
91
+ const activeTab = numInteger(attrs.activeTab, 0);
92
+ if (activeTab !== undefined)
93
+ view.activeTab = activeTab;
94
+ const visibility = enumToken(attrs.visibility, isVisibility);
95
+ if (visibility !== undefined && visibility !== 'visible')
96
+ view.visibility = visibility;
97
+ if (boolStrict(attrs.minimized))
98
+ view.minimized = true;
99
+ },
100
+ },
101
+ };
102
+ }
103
+ export function definedNamesPass() {
104
+ const drafts = [];
105
+ const refersTo = new TextCapture('definedName');
106
+ let pending;
107
+ return {
108
+ handlers: {
109
+ onOpen(name, attrs, selfClosing) {
110
+ if (localName(name) !== 'definedName' || attrs.name === undefined)
111
+ return;
112
+ if (attrs.name === '_xlnm._FilterDatabase')
113
+ return;
114
+ refersTo.open(localName(name), selfClosing);
115
+ pending = { name: attrs.name, localSheetId: numInteger(attrs.localSheetId, 0) ?? -1 };
116
+ if (attrs.comment !== undefined)
117
+ pending.comment = attrs.comment;
118
+ if (boolStrict(attrs.hidden))
119
+ pending.hidden = true;
120
+ },
121
+ onText(chunk) {
122
+ refersTo.text(chunk);
123
+ },
124
+ onClose(name) {
125
+ const text = refersTo.close(localName(name));
126
+ if (text === undefined || pending === undefined)
127
+ return;
128
+ drafts.push({ ...pending, refersTo: unmangleFunctions(text) });
129
+ pending = undefined;
130
+ },
131
+ },
132
+ closeEmptyElements: new Set(['definedName']),
133
+ result(sheetOrder) {
134
+ return drafts.map(({ localSheetId, ...draft }) => {
135
+ const scope = sheetOrder[localSheetId];
136
+ return scope === undefined ? draft : { ...draft, scope };
137
+ });
138
+ },
139
+ };
140
+ }
141
+ const CORE_PROPERTY_LOCAL_NAMES = new Set([
142
+ 'title',
143
+ 'creator',
144
+ 'lastModifiedBy',
145
+ 'created',
146
+ 'modified',
147
+ ]);
148
+ export function applyCoreProperties(workbook, xml) {
149
+ for (const { local, text } of capturedText(xml, CORE_PROPERTY_LOCAL_NAMES)) {
150
+ if (local === 'title')
151
+ workbook.properties.title = text;
152
+ else if (local === 'creator')
153
+ workbook.properties.creator = text;
154
+ else if (local === 'lastModifiedBy')
155
+ workbook.properties.lastModifiedBy = text;
156
+ else {
157
+ const date = parseDateText(text);
158
+ if (date !== null) {
159
+ if (local === 'created')
160
+ workbook.properties.created = date;
161
+ else
162
+ workbook.properties.modified = date;
163
+ }
164
+ }
165
+ }
166
+ }
167
+ export function applyAppProperties(workbook, xml) {
168
+ for (const { text } of capturedText(xml, 'Company'))
169
+ workbook.properties.company = text;
170
+ }
@@ -1,3 +1,4 @@
1
+ import type { DateEpoch } from '../../core/date.ts';
1
2
  import type { Worksheet } from '../../core/worksheet.ts';
2
3
  import { type SaxPass } from '../../xml/xml-read.ts';
3
4
  import type { XfStyle } from '../style/xf-style.ts';
@@ -10,4 +11,4 @@ import type { SharedString } from './cell-value.ts';
10
11
  * Offered as a pass because the worksheet is the largest part in a package and four other readers
11
12
  * want the same events, so the five share one parse of it rather than scanning it once each.
12
13
  */
13
- export declare function worksheetPass(sheet: Worksheet, sharedStrings: readonly SharedString[], xfStyles: ReadonlyArray<XfStyle>): SaxPass;
14
+ export declare function worksheetPass(sheet: Worksheet, sharedStrings: readonly SharedString[], xfStyles: ReadonlyArray<XfStyle>, dateEpoch: DateEpoch): SaxPass;