@shbernal/ts-xlsx 1.0.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 (223) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +230 -0
  3. package/dist/core/address.d.ts +49 -0
  4. package/dist/core/address.js +125 -0
  5. package/dist/core/autofilter.d.ts +55 -0
  6. package/dist/core/autofilter.js +48 -0
  7. package/dist/core/cell.d.ts +132 -0
  8. package/dist/core/cell.js +249 -0
  9. package/dist/core/color-resolution.d.ts +58 -0
  10. package/dist/core/color-resolution.js +170 -0
  11. package/dist/core/column.d.ts +87 -0
  12. package/dist/core/column.js +167 -0
  13. package/dist/core/comment-thread.d.ts +116 -0
  14. package/dist/core/comment-thread.js +62 -0
  15. package/dist/core/conditional-formatting-overlay.d.ts +15 -0
  16. package/dist/core/conditional-formatting-overlay.js +24 -0
  17. package/dist/core/conditional-formatting.d.ts +70 -0
  18. package/dist/core/conditional-formatting.js +35 -0
  19. package/dist/core/containers.d.ts +2 -0
  20. package/dist/core/containers.js +25 -0
  21. package/dist/core/data-validation-overlay.d.ts +28 -0
  22. package/dist/core/data-validation-overlay.js +56 -0
  23. package/dist/core/data-validation.d.ts +38 -0
  24. package/dist/core/data-validation.js +13 -0
  25. package/dist/core/date.d.ts +25 -0
  26. package/dist/core/date.js +58 -0
  27. package/dist/core/formula.d.ts +49 -0
  28. package/dist/core/formula.js +319 -0
  29. package/dist/core/grid-edits.d.ts +22 -0
  30. package/dist/core/grid-edits.js +206 -0
  31. package/dist/core/image.d.ts +76 -0
  32. package/dist/core/image.js +65 -0
  33. package/dist/core/internal.d.ts +11 -0
  34. package/dist/core/internal.js +29 -0
  35. package/dist/core/merge.d.ts +13 -0
  36. package/dist/core/merge.js +26 -0
  37. package/dist/core/modern-functions.d.ts +1 -0
  38. package/dist/core/modern-functions.js +165 -0
  39. package/dist/core/page-setup.d.ts +94 -0
  40. package/dist/core/page-setup.js +6 -0
  41. package/dist/core/pivot-table.d.ts +113 -0
  42. package/dist/core/pivot-table.js +249 -0
  43. package/dist/core/preserved.d.ts +58 -0
  44. package/dist/core/preserved.js +5 -0
  45. package/dist/core/protection.d.ts +67 -0
  46. package/dist/core/protection.js +68 -0
  47. package/dist/core/range.d.ts +112 -0
  48. package/dist/core/range.js +283 -0
  49. package/dist/core/row.d.ts +73 -0
  50. package/dist/core/row.js +135 -0
  51. package/dist/core/style.d.ts +246 -0
  52. package/dist/core/style.js +125 -0
  53. package/dist/core/table-style.d.ts +67 -0
  54. package/dist/core/table-style.js +90 -0
  55. package/dist/core/table.d.ts +194 -0
  56. package/dist/core/table.js +291 -0
  57. package/dist/core/theme.d.ts +90 -0
  58. package/dist/core/theme.js +272 -0
  59. package/dist/core/value.d.ts +115 -0
  60. package/dist/core/value.js +144 -0
  61. package/dist/core/workbook-protection.d.ts +27 -0
  62. package/dist/core/workbook-protection.js +25 -0
  63. package/dist/core/workbook.d.ts +528 -0
  64. package/dist/core/workbook.js +732 -0
  65. package/dist/core/worksheet-model.d.ts +34 -0
  66. package/dist/core/worksheet-model.js +100 -0
  67. package/dist/core/worksheet.d.ts +647 -0
  68. package/dist/core/worksheet.js +1025 -0
  69. package/dist/customui/errors.d.ts +15 -0
  70. package/dist/customui/errors.js +15 -0
  71. package/dist/customui/index.d.ts +2 -0
  72. package/dist/customui/index.js +7 -0
  73. package/dist/customui/ribbon.d.ts +86 -0
  74. package/dist/customui/ribbon.js +180 -0
  75. package/dist/entries/core.d.ts +23 -0
  76. package/dist/entries/core.js +20 -0
  77. package/dist/entries/csv.d.ts +2 -0
  78. package/dist/entries/csv.js +6 -0
  79. package/dist/entries/customui.d.ts +1 -0
  80. package/dist/entries/customui.js +3 -0
  81. package/dist/entries/errors.d.ts +7 -0
  82. package/dist/entries/errors.js +20 -0
  83. package/dist/entries/vba.d.ts +2 -0
  84. package/dist/entries/vba.js +7 -0
  85. package/dist/entries/xlsb.d.ts +1 -0
  86. package/dist/entries/xlsb.js +7 -0
  87. package/dist/entries/xlsx.d.ts +5 -0
  88. package/dist/entries/xlsx.js +18 -0
  89. package/dist/errors.d.ts +65 -0
  90. package/dist/errors.js +66 -0
  91. package/dist/index.d.ts +7 -0
  92. package/dist/index.js +19 -0
  93. package/dist/io/csv/read.d.ts +15 -0
  94. package/dist/io/csv/read.js +113 -0
  95. package/dist/io/csv/write.d.ts +28 -0
  96. package/dist/io/csv/write.js +124 -0
  97. package/dist/io/opc/errors.d.ts +46 -0
  98. package/dist/io/opc/errors.js +49 -0
  99. package/dist/io/opc/inflate.d.ts +15 -0
  100. package/dist/io/opc/inflate.js +91 -0
  101. package/dist/io/opc/namespaces.d.ts +18 -0
  102. package/dist/io/opc/namespaces.js +18 -0
  103. package/dist/io/opc/part-paths.d.ts +4 -0
  104. package/dist/io/opc/part-paths.js +35 -0
  105. package/dist/io/opc/read-opc.d.ts +24 -0
  106. package/dist/io/opc/read-opc.js +153 -0
  107. package/dist/io/opc/read-options.d.ts +10 -0
  108. package/dist/io/opc/read-options.js +7 -0
  109. package/dist/io/opc/rels.d.ts +15 -0
  110. package/dist/io/opc/rels.js +28 -0
  111. package/dist/io/opc/sniff-format.d.ts +27 -0
  112. package/dist/io/opc/sniff-format.js +92 -0
  113. package/dist/io/style/xf-style.d.ts +47 -0
  114. package/dist/io/style/xf-style.js +95 -0
  115. package/dist/io/xlsb/errors.d.ts +15 -0
  116. package/dist/io/xlsb/errors.js +15 -0
  117. package/dist/io/xlsb/formula.d.ts +48 -0
  118. package/dist/io/xlsb/formula.js +398 -0
  119. package/dist/io/xlsb/primitives.d.ts +86 -0
  120. package/dist/io/xlsb/primitives.js +230 -0
  121. package/dist/io/xlsb/ptg-functions.d.ts +16 -0
  122. package/dist/io/xlsb/ptg-functions.js +659 -0
  123. package/dist/io/xlsb/read-shared-strings.d.ts +2 -0
  124. package/dist/io/xlsb/read-shared-strings.js +22 -0
  125. package/dist/io/xlsb/read-styles.d.ts +4 -0
  126. package/dist/io/xlsb/read-styles.js +386 -0
  127. package/dist/io/xlsb/read-worksheet.d.ts +9 -0
  128. package/dist/io/xlsb/read-worksheet.js +301 -0
  129. package/dist/io/xlsb/read.d.ts +20 -0
  130. package/dist/io/xlsb/read.js +199 -0
  131. package/dist/io/xlsb/record-stream.d.ts +14 -0
  132. package/dist/io/xlsb/record-stream.js +56 -0
  133. package/dist/io/xlsb/record-types.d.ts +55 -0
  134. package/dist/io/xlsb/record-types.js +73 -0
  135. package/dist/io/xlsx/cell-accumulator.d.ts +25 -0
  136. package/dist/io/xlsx/cell-accumulator.js +172 -0
  137. package/dist/io/xlsx/cell-value.d.ts +32 -0
  138. package/dist/io/xlsx/cell-value.js +85 -0
  139. package/dist/io/xlsx/comments.d.ts +74 -0
  140. package/dist/io/xlsx/comments.js +243 -0
  141. package/dist/io/xlsx/conditional-formatting.d.ts +32 -0
  142. package/dist/io/xlsx/conditional-formatting.js +464 -0
  143. package/dist/io/xlsx/data-validation.d.ts +20 -0
  144. package/dist/io/xlsx/data-validation.js +258 -0
  145. package/dist/io/xlsx/edit-vba.d.ts +23 -0
  146. package/dist/io/xlsx/edit-vba.js +139 -0
  147. package/dist/io/xlsx/errors.d.ts +17 -0
  148. package/dist/io/xlsx/errors.js +17 -0
  149. package/dist/io/xlsx/hyperlinks.d.ts +42 -0
  150. package/dist/io/xlsx/hyperlinks.js +139 -0
  151. package/dist/io/xlsx/images.d.ts +34 -0
  152. package/dist/io/xlsx/images.js +218 -0
  153. package/dist/io/xlsx/namespaces.d.ts +55 -0
  154. package/dist/io/xlsx/namespaces.js +55 -0
  155. package/dist/io/xlsx/package-plan.d.ts +103 -0
  156. package/dist/io/xlsx/package-plan.js +168 -0
  157. package/dist/io/xlsx/pivot-read.d.ts +5 -0
  158. package/dist/io/xlsx/pivot-read.js +134 -0
  159. package/dist/io/xlsx/pivot.d.ts +12 -0
  160. package/dist/io/xlsx/pivot.js +141 -0
  161. package/dist/io/xlsx/read-rows.d.ts +85 -0
  162. package/dist/io/xlsx/read-rows.js +286 -0
  163. package/dist/io/xlsx/read-styles.d.ts +8 -0
  164. package/dist/io/xlsx/read-styles.js +551 -0
  165. package/dist/io/xlsx/read-worksheet.d.ts +4 -0
  166. package/dist/io/xlsx/read-worksheet.js +528 -0
  167. package/dist/io/xlsx/read.d.ts +32 -0
  168. package/dist/io/xlsx/read.js +680 -0
  169. package/dist/io/xlsx/relationships.d.ts +33 -0
  170. package/dist/io/xlsx/relationships.js +47 -0
  171. package/dist/io/xlsx/rich-runs.d.ts +13 -0
  172. package/dist/io/xlsx/rich-runs.js +59 -0
  173. package/dist/io/xlsx/rich-text.d.ts +7 -0
  174. package/dist/io/xlsx/rich-text.js +23 -0
  175. package/dist/io/xlsx/shared-formulas.d.ts +6 -0
  176. package/dist/io/xlsx/shared-formulas.js +52 -0
  177. package/dist/io/xlsx/shared-strings-read.d.ts +2 -0
  178. package/dist/io/xlsx/shared-strings-read.js +70 -0
  179. package/dist/io/xlsx/shared-strings.d.ts +17 -0
  180. package/dist/io/xlsx/shared-strings.js +50 -0
  181. package/dist/io/xlsx/sheet-properties.d.ts +13 -0
  182. package/dist/io/xlsx/sheet-properties.js +211 -0
  183. package/dist/io/xlsx/styles.d.ts +138 -0
  184. package/dist/io/xlsx/styles.js +821 -0
  185. package/dist/io/xlsx/tables.d.ts +9 -0
  186. package/dist/io/xlsx/tables.js +208 -0
  187. package/dist/io/xlsx/threaded-comments.d.ts +102 -0
  188. package/dist/io/xlsx/threaded-comments.js +308 -0
  189. package/dist/io/xlsx/workbook-xml.d.ts +12 -0
  190. package/dist/io/xlsx/workbook-xml.js +353 -0
  191. package/dist/io/xlsx/worksheet-xml.d.ts +86 -0
  192. package/dist/io/xlsx/worksheet-xml.js +643 -0
  193. package/dist/io/xlsx/write-stream.d.ts +171 -0
  194. package/dist/io/xlsx/write-stream.js +399 -0
  195. package/dist/io/xlsx/write.d.ts +81 -0
  196. package/dist/io/xlsx/write.js +396 -0
  197. package/dist/io/xlsx/x14-ext.d.ts +9 -0
  198. package/dist/io/xlsx/x14-ext.js +12 -0
  199. package/dist/vba/cfb-writer.d.ts +19 -0
  200. package/dist/vba/cfb-writer.js +277 -0
  201. package/dist/vba/cfb.d.ts +16 -0
  202. package/dist/vba/cfb.js +324 -0
  203. package/dist/vba/codepage.d.ts +18 -0
  204. package/dist/vba/codepage.js +87 -0
  205. package/dist/vba/errors.d.ts +24 -0
  206. package/dist/vba/errors.js +24 -0
  207. package/dist/vba/index.d.ts +5 -0
  208. package/dist/vba/index.js +15 -0
  209. package/dist/vba/ms-ovba.d.ts +12 -0
  210. package/dist/vba/ms-ovba.js +176 -0
  211. package/dist/vba/project-editor.d.ts +62 -0
  212. package/dist/vba/project-editor.js +377 -0
  213. package/dist/vba/project.d.ts +45 -0
  214. package/dist/vba/project.js +160 -0
  215. package/dist/vba/vba-encoding.d.ts +14 -0
  216. package/dist/vba/vba-encoding.js +39 -0
  217. package/dist/xml/errors.d.ts +15 -0
  218. package/dist/xml/errors.js +15 -0
  219. package/dist/xml/xml-read.d.ts +107 -0
  220. package/dist/xml/xml-read.js +283 -0
  221. package/dist/xml/xml.d.ts +41 -0
  222. package/dist/xml/xml.js +86 -0
  223. package/package.json +117 -0
@@ -0,0 +1,206 @@
1
+ // Structural-edit machinery: the splice arithmetic that inserts or deletes whole rows and columns
2
+ // and keeps everything anchored to the grid moving in step — line metadata, merged ranges, tables,
3
+ // anchored images, and shared-formula clones. It is isolated from Worksheet because it is pure grid
4
+ // mechanics: it holds the sheet's storage containers by reference and mutates them in place, and
5
+ // touches none of the public cell API. Worksheet builds the cells an insert introduces, then hands
6
+ // the pre-built rows (or the raw column values) here for the shift.
7
+ import { decodeAddress, decodeRange, encodeAddress } from "./address.js";
8
+ import { Cell, copyCellContent } from "./cell.js";
9
+ import { replaceContents } from "./containers.js";
10
+ import { isOneCellAnchor } from "./image.js";
11
+ import { isSharedFormulaValue } from "./value.js";
12
+ // The shift rule shared by every re-anchoring pass: a coordinate before the edit stays put, one at or
13
+ // after the edited span shifts by `delta`, and one inside a deleted span clamps to the cut line (`start`).
14
+ function shiftIndex(v, start, count, delta) {
15
+ return v < start ? v : v >= start + count ? v + delta : start;
16
+ }
17
+ export class GridEdits {
18
+ #rows;
19
+ #rowProperties;
20
+ #columns;
21
+ #merges;
22
+ #mergeRects;
23
+ #tables;
24
+ #images;
25
+ constructor(storage) {
26
+ this.#rows = storage.rows;
27
+ this.#rowProperties = storage.rowProperties;
28
+ this.#columns = storage.columns;
29
+ this.#merges = storage.merges;
30
+ this.#mergeRects = storage.mergeRects;
31
+ this.#tables = storage.tables;
32
+ this.#images = storage.images;
33
+ }
34
+ // Apply a delete-then-insert to the row grid: surviving rows below the edit shift by
35
+ // `inserted.length - count`, deleted rows drop out, and the pre-built inserted rows land at `start`.
36
+ // Row metadata and merged ranges shift the same way, so a formatting-only row or a covered merge
37
+ // stays aligned with the data it describes.
38
+ spliceRows(start, count, inserted) {
39
+ const delta = inserted.length - count;
40
+ const shifted = new Map();
41
+ for (const [row, cols] of this.#rows) {
42
+ if (row < start)
43
+ shifted.set(row, cols);
44
+ else if (row >= start + count)
45
+ shifted.set(row + delta, this.#relocateRow(cols, row + delta));
46
+ }
47
+ inserted.forEach((cols, i) => {
48
+ shifted.set(start + i, this.#relocateRow(cols, start + i));
49
+ });
50
+ this.#rows.clear();
51
+ for (const [row, cols] of shifted)
52
+ this.#rows.set(row, cols);
53
+ this.#shiftLineProperties(this.#rowProperties, start, count, delta);
54
+ this.#shiftMerges('row', start, count, delta);
55
+ this.#shiftTables('row', start, count, delta);
56
+ this.#shiftImages('row', start, count, delta);
57
+ this.#reanchorSharedFormulas('row', start, count, delta);
58
+ }
59
+ // Apply a delete-then-insert to the column grid: cells left of the edit stay, cells at or beyond the
60
+ // deleted span shift by `inserts.length - count` carrying their content, and the inserted column
61
+ // values materialise as fresh cells at `start`. Column metadata, merges, tables, images, and
62
+ // shared-formula clones re-anchor the same way.
63
+ spliceColumns(start, count, inserts) {
64
+ const delta = inserts.length - count;
65
+ for (const [row, cols] of this.#rows) {
66
+ const shifted = new Map();
67
+ for (const [col, cell] of cols) {
68
+ if (col < start) {
69
+ shifted.set(col, cell);
70
+ }
71
+ else if (col >= start + count) {
72
+ const dest = col + delta;
73
+ const moved = new Cell(row, dest);
74
+ copyCellContent(cell, moved);
75
+ shifted.set(dest, moved);
76
+ }
77
+ }
78
+ inserts.forEach((values, i) => {
79
+ const value = values[row - 1];
80
+ if (value !== undefined) {
81
+ const cell = new Cell(row, start + i);
82
+ cell.value = value;
83
+ shifted.set(start + i, cell);
84
+ }
85
+ });
86
+ this.#rows.set(row, shifted);
87
+ }
88
+ this.#shiftLineProperties(this.#columns, start, count, delta);
89
+ this.#shiftMerges('col', start, count, delta);
90
+ this.#shiftTables('col', start, count, delta);
91
+ this.#shiftImages('col', start, count, delta);
92
+ this.#reanchorSharedFormulas('col', start, count, delta);
93
+ }
94
+ // Rebuild a row's cells at a new row index. `Cell` fixes its position at construction, so a moved
95
+ // row is a fresh set of cells at `destRow` carrying the originals' content.
96
+ #relocateRow(cols, destRow) {
97
+ const moved = new Map();
98
+ for (const [col, cell] of cols) {
99
+ if (cell.row === destRow) {
100
+ moved.set(col, cell);
101
+ }
102
+ else {
103
+ const copy = new Cell(destRow, col);
104
+ copyCellContent(cell, copy);
105
+ moved.set(col, copy);
106
+ }
107
+ }
108
+ return moved;
109
+ }
110
+ // Re-anchor shared-formula clones through a splice on the given axis. A clone stores its master's
111
+ // absolute address; when the splice shifts the master, that stored address goes stale and the writer
112
+ // would reject the clone as orphaned. Applying the same shift the grid used keeps each clone pointed
113
+ // at its master's new cell. A master whose axis coordinate falls in the deleted span clamps to the
114
+ // cut line like a merge edge — a genuinely orphaned clone the writer then reports legibly.
115
+ #reanchorSharedFormulas(axis, start, count, delta) {
116
+ for (const cols of this.#rows.values()) {
117
+ for (const cell of cols.values()) {
118
+ const value = cell.value;
119
+ if (!isSharedFormulaValue(value))
120
+ continue;
121
+ const master = decodeAddress(value.sharedFormula);
122
+ if (master.col === undefined || master.row === undefined)
123
+ continue;
124
+ const anchored = axis === 'row'
125
+ ? encodeAddress(master.col, shiftIndex(master.row, start, count, delta))
126
+ : encodeAddress(shiftIndex(master.col, start, count, delta), master.row);
127
+ if (anchored === value.sharedFormula)
128
+ continue;
129
+ const reanchored = { ...value, sharedFormula: anchored };
130
+ cell.value = reanchored;
131
+ }
132
+ }
133
+ }
134
+ // Shift a line-metadata map (row properties keyed by row, or column properties keyed by column)
135
+ // through a splice: entries before the edit stay, entries within the deleted span drop, entries
136
+ // after shift by `delta`. Mutates the map in place.
137
+ #shiftLineProperties(map, start, count, delta) {
138
+ const shifted = new Map();
139
+ for (const [index, value] of map) {
140
+ if (index < start)
141
+ shifted.set(index, value);
142
+ else if (index >= start + count)
143
+ shifted.set(index + delta, value);
144
+ }
145
+ map.clear();
146
+ for (const [index, value] of shifted)
147
+ map.set(index, value);
148
+ }
149
+ // Re-anchor merged ranges through a row or column splice. A range wholly before the edit is
150
+ // untouched; one wholly after shifts by `nInserts - count`; one whose covered rows/columns are
151
+ // entirely deleted is dropped. A range straddling the cut is a genuinely ambiguous geometry — its
152
+ // edges are clamped to the cut line as a best effort. Unbounded whole-row/column merges carry no
153
+ // rectangle and pass through unchanged.
154
+ #shiftMerges(axis, start, count, delta) {
155
+ const shift = (v) => shiftIndex(v, start, count, delta);
156
+ const merges = [];
157
+ const rects = [];
158
+ for (const range of this.#merges) {
159
+ const { top, left, bottom, right } = decodeRange(range);
160
+ if (top === undefined || left === undefined || bottom === undefined || right === undefined) {
161
+ merges.push(range);
162
+ continue;
163
+ }
164
+ const [lo, hi] = axis === 'row' ? [top, bottom] : [left, right];
165
+ if (lo >= start && hi < start + count)
166
+ continue;
167
+ const rect = axis === 'row'
168
+ ? { top: shift(top), left, bottom: shift(bottom), right }
169
+ : { top, left: shift(left), bottom, right: shift(right) };
170
+ rects.push(rect);
171
+ merges.push(`${encodeAddress(rect.left, rect.top)}:${encodeAddress(rect.right, rect.bottom)}`);
172
+ }
173
+ replaceContents(this.#merges, merges);
174
+ replaceContents(this.#mergeRects, rects);
175
+ }
176
+ // Re-pin the sheet's tables through a splice on the given axis, dropping any table a delete leaves
177
+ // with no row to occupy. `Table` owns the shift arithmetic; the sheet only prunes the casualties.
178
+ #shiftTables(axis, start, count, delta) {
179
+ const survivors = this.#tables.filter((table) => axis === 'row'
180
+ ? table.shiftRows(start, count, delta)
181
+ : table.shiftColumns(start, count, delta));
182
+ replaceContents(this.#tables, survivors);
183
+ }
184
+ // Re-pin anchored images through a splice. An anchor point moves like a merge edge: a point before
185
+ // the cut stays, one at or after it shifts by `delta`, and one inside a deleted span clamps to the
186
+ // cut line. Grid points are 0-based, so each is converted to the 1-based coordinate the shared
187
+ // shift arithmetic uses and back. An anchor whose points both move keeps its size; an anchor
188
+ // straddling the cut grows or shrinks, matching how Excel reflows a picture across inserted rows.
189
+ #shiftImages(axis, start, count, delta) {
190
+ const shiftPoint = (point) => {
191
+ const zeroBased = axis === 'row' ? point.row : point.col;
192
+ const shifted = shiftIndex(zeroBased + 1, start, count, delta) - 1;
193
+ if (shifted === zeroBased)
194
+ return point;
195
+ return axis === 'row' ? { ...point, row: shifted } : { ...point, col: shifted };
196
+ };
197
+ const moved = this.#images.map((image) => {
198
+ const from = shiftPoint(image.anchor.from);
199
+ const anchor = isOneCellAnchor(image.anchor)
200
+ ? { ...image.anchor, from }
201
+ : { ...image.anchor, from, to: shiftPoint(image.anchor.to) };
202
+ return { imageId: image.imageId, anchor };
203
+ });
204
+ replaceContents(this.#images, moved);
205
+ }
206
+ }
@@ -0,0 +1,76 @@
1
+ /** A point in the drawing grid: a 0-based column and row, plus an EMU offset into that cell.
2
+ * The offsets default to zero, pinning the point to the cell's top-left corner. */
3
+ export interface AnchorPoint {
4
+ /** 0-based column index (column A is 0). */
5
+ readonly col: number;
6
+ /** 0-based row index (row 1 is 0). */
7
+ readonly row: number;
8
+ /** Horizontal offset into the cell, in EMUs (914400 per inch). Defaults to 0. */
9
+ readonly colOff?: number;
10
+ /** Vertical offset into the cell, in EMUs. Defaults to 0. */
11
+ readonly rowOff?: number;
12
+ }
13
+ /** EMUs per pixel at Excel's notional 96 DPI (914400 EMU/inch ÷ 96 px/inch). The conversion is
14
+ * DPI-independent by construction: a pixel extent is a fixed physical size regardless of screen. */
15
+ export declare const PX_TO_EMU = 9525;
16
+ /** How a two-cell-anchored image tracks edits to the cells it spans. `twoCell` moves and resizes with
17
+ * them; `oneCell` moves but keeps its size; `absolute` is pinned to the page and does neither. Excel
18
+ * defaults to `oneCell` when the attribute is omitted. */
19
+ export type ImageEditAs = 'oneCell' | 'twoCell' | 'absolute';
20
+ /** A fixed image size in EMUs — the extent of a one-cell anchor, which pixel dimensions convert into
21
+ * via {@link PX_TO_EMU}. */
22
+ export interface Extent {
23
+ readonly cx: number;
24
+ readonly cy: number;
25
+ }
26
+ /** A two-cell anchor: the image's top-left (`from`) and bottom-right (`to`) grid points. The image
27
+ * fills the rectangle between them and reflows as the intervening rows/columns resize; `editAs`
28
+ * selects how strictly it follows. */
29
+ export interface TwoCellAnchor {
30
+ readonly from: AnchorPoint;
31
+ readonly to: AnchorPoint;
32
+ readonly editAs?: ImageEditAs;
33
+ /** Clockwise rotation in 1/60000 of a degree (`2700000` = 45°), preserved from a loaded file. */
34
+ readonly rotation?: number;
35
+ }
36
+ /** A one-cell anchor: a single top-left grid point plus a fixed extent. The image keeps its size as
37
+ * the grid resizes, moving only with its anchor cell. `editAs` is a two-cell-only attribute and has
38
+ * no place here. */
39
+ export interface OneCellAnchor {
40
+ readonly from: AnchorPoint;
41
+ readonly ext: Extent;
42
+ /** Clockwise rotation in 1/60000 of a degree (`2700000` = 45°), preserved from a loaded file. */
43
+ readonly rotation?: number;
44
+ }
45
+ /** Where an image sits on the grid: a rectangle between two cells, or a point plus a fixed extent. */
46
+ export type ImageAnchor = TwoCellAnchor | OneCellAnchor;
47
+ /** Narrow an anchor to its one-cell (fixed-extent) form; the complement is {@link TwoCellAnchor}. */
48
+ export declare function isOneCellAnchor(anchor: ImageAnchor): anchor is OneCellAnchor;
49
+ /** A column's width in characters of the default font, or `undefined` to take Excel's default. */
50
+ export type ColumnWidthLookup = (col: number) => number | undefined;
51
+ /** A row's height in points, or `undefined` to take Excel's default. */
52
+ export type RowHeightLookup = (row: number) => number | undefined;
53
+ /** Resolve a possibly-fractional anchor point to the cell it floors to plus a sub-cell EMU offset
54
+ * scaled by that cell's real width/height, so `col: 3.5` lands halfway across column 3 regardless of
55
+ * the column's size. An already-integer point keeps a zero offset (unless one was given). The two
56
+ * lookups supply each column/row's size; a size they leave `undefined` falls back to Excel's default. */
57
+ export declare function resolveAnchorPoint(point: AnchorPoint, columnWidth: ColumnWidthLookup, rowHeight: RowHeightLookup): AnchorPoint;
58
+ /** An image pinned to a worksheet: which workbook media it shows (`imageId`) and where. */
59
+ export interface AnchoredImage {
60
+ /** Index into the workbook's media registry (the id {@link Workbook.addImage} returned). */
61
+ readonly imageId: number;
62
+ readonly anchor: ImageAnchor;
63
+ }
64
+ /** A picture's bytes and its file kind, as held in the workbook's media registry. */
65
+ export interface WorkbookImage {
66
+ /** Lower-case file extension without a dot — `"png"`, `"jpeg"`, `"gif"`. Drives the media part's
67
+ * name and content type. */
68
+ readonly extension: string;
69
+ readonly data: Uint8Array;
70
+ }
71
+ /** Reduce a caller-supplied extension to the bare, lower-case alphanumeric token OOXML expects for a
72
+ * media part's name and `<Default Extension>`. A leading dot (`".png"`), a URL query string
73
+ * (`"png?alt=media"`), or any other separator a real-world filename/URL drags in is stripped to the
74
+ * leading run of alphanumerics; a missing or all-punctuation hint falls back to sniffing the bytes'
75
+ * magic number, so the package is always well-formed. */
76
+ export declare function normalizeImageExtension(extension: string | undefined, data: Uint8Array): string;
@@ -0,0 +1,65 @@
1
+ // Anchored images: the model for a picture pinned to a worksheet's grid.
2
+ //
3
+ // The image *bytes* live once on the workbook (a small media registry, addressed by a numeric id);
4
+ // a worksheet then anchors that image to a rectangle of cells. Storing the bytes centrally means the
5
+ // same picture used on two sheets — a logo in a header band, say — is one media part, not two.
6
+ /** EMUs per pixel at Excel's notional 96 DPI (914400 EMU/inch ÷ 96 px/inch). The conversion is
7
+ * DPI-independent by construction: a pixel extent is a fixed physical size regardless of screen. */
8
+ export const PX_TO_EMU = 9525;
9
+ /** Narrow an anchor to its one-cell (fixed-extent) form; the complement is {@link TwoCellAnchor}. */
10
+ export function isOneCellAnchor(anchor) {
11
+ return 'ext' in anchor;
12
+ }
13
+ // Sub-cell anchor geometry. Excel measures a column in characters of the default font (~7 px each at
14
+ // 96 DPI) and a row in points (1/72 inch); a column or row that sets no size falls back to Excel's
15
+ // own defaults. These constants live here, beside the anchor model they serve, rather than in the
16
+ // Worksheet that merely supplies the per-column/row sizes.
17
+ const CHAR_WIDTH_PX = 7;
18
+ const EMU_PER_POINT = 12700;
19
+ const DEFAULT_COL_WIDTH_CHARS = 8.43;
20
+ const DEFAULT_ROW_HEIGHT_POINTS = 15;
21
+ /** Resolve a possibly-fractional anchor point to the cell it floors to plus a sub-cell EMU offset
22
+ * scaled by that cell's real width/height, so `col: 3.5` lands halfway across column 3 regardless of
23
+ * the column's size. An already-integer point keeps a zero offset (unless one was given). The two
24
+ * lookups supply each column/row's size; a size they leave `undefined` falls back to Excel's default. */
25
+ export function resolveAnchorPoint(point, columnWidth, rowHeight) {
26
+ const col = Math.floor(point.col);
27
+ const row = Math.floor(point.row);
28
+ const colWidthEmu = Math.round((columnWidth(col) ?? DEFAULT_COL_WIDTH_CHARS) * CHAR_WIDTH_PX * PX_TO_EMU);
29
+ const rowHeightEmu = Math.round((rowHeight(row) ?? DEFAULT_ROW_HEIGHT_POINTS) * EMU_PER_POINT);
30
+ const colOff = (point.colOff ?? 0) + Math.round((point.col - col) * colWidthEmu);
31
+ const rowOff = (point.rowOff ?? 0) + Math.round((point.row - row) * rowHeightEmu);
32
+ return { col, row, colOff, rowOff };
33
+ }
34
+ // Leading magic bytes for the raster formats a spreadsheet embeds, most-specific first. Used to infer
35
+ // an extension when the caller supplies none, so a package never declares an `image/undefined` type.
36
+ const IMAGE_MAGIC = [
37
+ { ext: 'png', sig: [0x89, 0x50, 0x4e, 0x47] },
38
+ { ext: 'jpeg', sig: [0xff, 0xd8, 0xff] },
39
+ { ext: 'gif', sig: [0x47, 0x49, 0x46] },
40
+ { ext: 'bmp', sig: [0x42, 0x4d] },
41
+ { ext: 'tiff', sig: [0x49, 0x49, 0x2a, 0x00] },
42
+ { ext: 'tiff', sig: [0x4d, 0x4d, 0x00, 0x2a] },
43
+ ];
44
+ function sniffImageExtension(data) {
45
+ for (const { ext, sig } of IMAGE_MAGIC) {
46
+ if (sig.every((b, i) => data[i] === b))
47
+ return ext;
48
+ }
49
+ // An unrecognised blob still needs a valid media name and content type; png keeps the package
50
+ // well-formed rather than emitting a `<Default>` with no or a bogus extension.
51
+ return 'png';
52
+ }
53
+ /** Reduce a caller-supplied extension to the bare, lower-case alphanumeric token OOXML expects for a
54
+ * media part's name and `<Default Extension>`. A leading dot (`".png"`), a URL query string
55
+ * (`"png?alt=media"`), or any other separator a real-world filename/URL drags in is stripped to the
56
+ * leading run of alphanumerics; a missing or all-punctuation hint falls back to sniffing the bytes'
57
+ * magic number, so the package is always well-formed. */
58
+ export function normalizeImageExtension(extension, data) {
59
+ if (typeof extension === 'string') {
60
+ const token = extension.toLowerCase().match(/[a-z0-9]+/)?.[0];
61
+ if (token !== undefined)
62
+ return token;
63
+ }
64
+ return sniffImageExtension(data);
65
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Keys the codec-only operations on `Workbook` and `Worksheet` (see `WorkbookInternals` /
3
+ * `WorksheetInternals`, declared beside their classes).
4
+ */
5
+ export declare const INTERNAL: unique symbol;
6
+ /**
7
+ * Keys a `Cell`'s link to a named cell style — its OOXML `xfId`. A single hidden property rather than
8
+ * a channel object, so it stays a prototype accessor: cells are the one model class allocated in the
9
+ * millions, and a per-instance internals object would be a real cost for state most cells never carry.
10
+ */
11
+ export declare const NAMED_STYLE_ID: unique symbol;
@@ -0,0 +1,29 @@
1
+ // The codec's back channel into the model.
2
+ //
3
+ // A reader has to push state into a `Workbook` that no authoring path can produce: a `<dxfs>` table
4
+ // whose indices existing rules already point at, a theme part carried as opaque bytes, a protection
5
+ // credential in finished agile form with no recoverable password. The streaming writer likewise has
6
+ // to drop a row's cells the moment they are serialised. All of that used to be public methods on the
7
+ // model classes — so they shipped in the `.d.ts`, appeared in the generated API reference, and a
8
+ // caller who tried one put the workbook in a state nothing else could reach or repair. There was no
9
+ // authoring/codec boundary at all: the model class *was* the codec's mutation interface.
10
+ //
11
+ // These symbols are that boundary. The operations still live on the classes and still mutate exactly
12
+ // the state they always did — this moves no data — but reaching them requires a symbol that is not on
13
+ // the public barrel and, because `package.json` exposes only the root entry, is not importable from
14
+ // outside the package at all. Inside the tree, the import is the audit trail: `grep` for this module
15
+ // and you have the complete list of code that can restore preserved state.
16
+ //
17
+ // Prefer an ordinary public method whenever a caller could reasonably want the operation. This is for
18
+ // operations that are *only* meaningful mid-deserialisation.
19
+ /**
20
+ * Keys the codec-only operations on `Workbook` and `Worksheet` (see `WorkbookInternals` /
21
+ * `WorksheetInternals`, declared beside their classes).
22
+ */
23
+ export const INTERNAL = Symbol('ts-xlsx codec channel');
24
+ /**
25
+ * Keys a `Cell`'s link to a named cell style — its OOXML `xfId`. A single hidden property rather than
26
+ * a channel object, so it stays a prototype accessor: cells are the one model class allocated in the
27
+ * millions, and a per-instance internals object would be a real cost for state most cells never carry.
28
+ */
29
+ export const NAMED_STYLE_ID = Symbol('ts-xlsx named style link');
@@ -0,0 +1,13 @@
1
+ /** A merged region as inclusive 1-based grid bounds. */
2
+ export interface MergeRect {
3
+ readonly top: number;
4
+ readonly left: number;
5
+ readonly bottom: number;
6
+ readonly right: number;
7
+ }
8
+ /** Whether two inclusive grid rectangles share at least one cell. */
9
+ export declare function rectsOverlap(a: MergeRect, b: MergeRect): boolean;
10
+ /** Decode an OOXML `sqref` (one or more space-separated ranges) into containment rectangles. A whole
11
+ * column or row leaves one axis unbounded, so its missing edges open to `Infinity` rather than
12
+ * clamping — a cell anywhere down the column still resolves inside it. */
13
+ export declare function decodeSqrefRects(sqref: string): MergeRect[];
@@ -0,0 +1,26 @@
1
+ // Inclusive grid rectangles and the geometry a worksheet uses to reason about merged regions and the
2
+ // `sqref` ranges that overlays (data validations, conditional formats) apply to: overlap detection and
3
+ // decoding an OOXML `sqref` into containment rectangles.
4
+ import { decodeRange } from "./address.js";
5
+ /** Whether two inclusive grid rectangles share at least one cell. */
6
+ export function rectsOverlap(a, b) {
7
+ return a.left <= b.right && b.left <= a.right && a.top <= b.bottom && b.top <= a.bottom;
8
+ }
9
+ /** Decode an OOXML `sqref` (one or more space-separated ranges) into containment rectangles. A whole
10
+ * column or row leaves one axis unbounded, so its missing edges open to `Infinity` rather than
11
+ * clamping — a cell anywhere down the column still resolves inside it. */
12
+ export function decodeSqrefRects(sqref) {
13
+ const rects = [];
14
+ for (const part of sqref.split(/\s+/)) {
15
+ if (part === '')
16
+ continue;
17
+ const { top, left, bottom, right } = decodeRange(part);
18
+ rects.push({
19
+ top: top ?? 1,
20
+ left: left ?? 1,
21
+ bottom: bottom ?? Infinity,
22
+ right: right ?? Infinity,
23
+ });
24
+ }
25
+ return rects;
26
+ }
@@ -0,0 +1 @@
1
+ export declare const MODERN_FUNCTIONS: ReadonlySet<string>;
@@ -0,0 +1,165 @@
1
+ // The post-2007 functions Excel persists with an `_xlfn.` prefix, keyed by their uppercased name.
2
+ // OOXML froze its function grammar around Excel 2007; everything Microsoft added since is unknown to
3
+ // older readers under its bare name, so the writer stores it prefixed and the reader strips the prefix
4
+ // back — the mangling in `formula.ts` is the single place that applies and removes it. That mangler
5
+ // treats '.' as part of a function name, so both the plain modern functions and the dotted 2010
6
+ // statistical rename family below are matched as whole names and prefixed.
7
+ export const MODERN_FUNCTIONS = new Set([
8
+ // Dynamic arrays (Excel 365)
9
+ 'FILTER',
10
+ 'SORT',
11
+ 'SORTBY',
12
+ 'UNIQUE',
13
+ 'SEQUENCE',
14
+ 'RANDARRAY',
15
+ 'XLOOKUP',
16
+ 'XMATCH',
17
+ // LAMBDA and its helpers
18
+ 'LAMBDA',
19
+ 'LET',
20
+ 'BYROW',
21
+ 'BYCOL',
22
+ 'MAKEARRAY',
23
+ 'MAP',
24
+ 'REDUCE',
25
+ 'SCAN',
26
+ 'ISOMITTED',
27
+ // Array shaping (Excel 365)
28
+ 'VSTACK',
29
+ 'HSTACK',
30
+ 'TOROW',
31
+ 'TOCOL',
32
+ 'WRAPROWS',
33
+ 'WRAPCOLS',
34
+ 'TAKE',
35
+ 'DROP',
36
+ 'EXPAND',
37
+ 'CHOOSEROWS',
38
+ 'CHOOSECOLS',
39
+ // Text (Excel 2019 / 365)
40
+ 'TEXTJOIN',
41
+ 'CONCAT',
42
+ 'TEXTBEFORE',
43
+ 'TEXTAFTER',
44
+ 'TEXTSPLIT',
45
+ 'ARRAYTOTEXT',
46
+ 'VALUETOTEXT',
47
+ // Logical and conditional aggregation (Excel 2016 / 2019)
48
+ 'IFS',
49
+ 'SWITCH',
50
+ 'MAXIFS',
51
+ 'MINIFS',
52
+ // Other bare-name functions added after the frozen grammar (Excel 2010 / 2013) — trigonometric,
53
+ // bitwise, engineering, information, and math/financial additions. Their names carry no '.', so
54
+ // they need no tokenizer work; they simply have to be recognised as modern to earn the prefix.
55
+ 'AGGREGATE',
56
+ 'ACOT',
57
+ 'ACOTH',
58
+ 'COT',
59
+ 'COTH',
60
+ 'CSC',
61
+ 'CSCH',
62
+ 'SEC',
63
+ 'SECH',
64
+ 'ARABIC',
65
+ 'BASE',
66
+ 'DECIMAL',
67
+ 'COMBINA',
68
+ 'PERMUTATIONA',
69
+ 'GAMMA',
70
+ 'GAUSS',
71
+ 'PHI',
72
+ 'MUNIT',
73
+ 'BITAND',
74
+ 'BITOR',
75
+ 'BITXOR',
76
+ 'BITLSHIFT',
77
+ 'BITRSHIFT',
78
+ 'IMCOSH',
79
+ 'IMCOT',
80
+ 'IMCSC',
81
+ 'IMCSCH',
82
+ 'IMSEC',
83
+ 'IMSECH',
84
+ 'IMSINH',
85
+ 'IMTAN',
86
+ 'DAYS',
87
+ 'ISOWEEKNUM',
88
+ 'IFNA',
89
+ 'NUMBERVALUE',
90
+ 'SHEET',
91
+ 'SHEETS',
92
+ 'FORMULATEXT',
93
+ 'ISFORMULA',
94
+ 'ENCODEURL',
95
+ 'WEBSERVICE',
96
+ 'FILTERXML',
97
+ 'UNICHAR',
98
+ 'UNICODE',
99
+ 'XOR',
100
+ 'PDURATION',
101
+ 'RRI',
102
+ // The Excel 2010 statistical-consistency rename family and the handful of other post-2007
103
+ // functions whose canonical names contain a '.'. They carry the same `_xlfn.` prefix; the whole
104
+ // dotted name is stored, e.g. `_xlfn.NORM.DIST`, `_xlfn.T.DIST.2T`.
105
+ 'BETA.DIST',
106
+ 'BETA.INV',
107
+ 'BINOM.DIST',
108
+ 'BINOM.DIST.RANGE',
109
+ 'BINOM.INV',
110
+ 'CHISQ.DIST',
111
+ 'CHISQ.DIST.RT',
112
+ 'CHISQ.INV',
113
+ 'CHISQ.INV.RT',
114
+ 'CHISQ.TEST',
115
+ 'CONFIDENCE.NORM',
116
+ 'CONFIDENCE.T',
117
+ 'COVARIANCE.P',
118
+ 'COVARIANCE.S',
119
+ 'EXPON.DIST',
120
+ 'F.DIST',
121
+ 'F.DIST.RT',
122
+ 'F.INV',
123
+ 'F.INV.RT',
124
+ 'F.TEST',
125
+ 'GAMMA.DIST',
126
+ 'GAMMA.INV',
127
+ 'GAMMALN.PRECISE',
128
+ 'HYPGEOM.DIST',
129
+ 'LOGNORM.DIST',
130
+ 'LOGNORM.INV',
131
+ 'MODE.MULT',
132
+ 'MODE.SNGL',
133
+ 'NEGBINOM.DIST',
134
+ 'NORM.DIST',
135
+ 'NORM.INV',
136
+ 'NORM.S.DIST',
137
+ 'NORM.S.INV',
138
+ 'PERCENTILE.EXC',
139
+ 'PERCENTILE.INC',
140
+ 'PERCENTRANK.EXC',
141
+ 'PERCENTRANK.INC',
142
+ 'POISSON.DIST',
143
+ 'QUARTILE.EXC',
144
+ 'QUARTILE.INC',
145
+ 'RANK.AVG',
146
+ 'RANK.EQ',
147
+ 'SKEW.P',
148
+ 'STDEV.P',
149
+ 'STDEV.S',
150
+ 'T.DIST',
151
+ 'T.DIST.2T',
152
+ 'T.DIST.RT',
153
+ 'T.INV',
154
+ 'T.INV.2T',
155
+ 'T.TEST',
156
+ 'VAR.P',
157
+ 'VAR.S',
158
+ 'WEIBULL.DIST',
159
+ 'Z.TEST',
160
+ 'CEILING.PRECISE',
161
+ 'FLOOR.PRECISE',
162
+ 'ISO.CEILING',
163
+ 'ERF.PRECISE',
164
+ 'ERFC.PRECISE',
165
+ ]);