@yuanliwei/exceljs 4.4.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 (185) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +3024 -0
  3. package/README_zh.md +2878 -0
  4. package/excel.js +13 -0
  5. package/index.d.ts +2040 -0
  6. package/index.ts +2 -0
  7. package/lib/csv/csv.js +191 -0
  8. package/lib/csv/line-buffer.js +74 -0
  9. package/lib/csv/stream-converter.js +135 -0
  10. package/lib/doc/anchor.js +91 -0
  11. package/lib/doc/cell.js +1124 -0
  12. package/lib/doc/column.js +320 -0
  13. package/lib/doc/data/theme1.json +234 -0
  14. package/lib/doc/data-validations.js +19 -0
  15. package/lib/doc/defined-names.js +196 -0
  16. package/lib/doc/enums.js +48 -0
  17. package/lib/doc/image.js +59 -0
  18. package/lib/doc/modelcontainer.js +18 -0
  19. package/lib/doc/note.js +65 -0
  20. package/lib/doc/pivot-table.js +132 -0
  21. package/lib/doc/range.js +257 -0
  22. package/lib/doc/row.js +415 -0
  23. package/lib/doc/table.js +465 -0
  24. package/lib/doc/workbook.js +224 -0
  25. package/lib/doc/worksheet.js +949 -0
  26. package/lib/exceljs.bare.js +13 -0
  27. package/lib/exceljs.browser.js +36 -0
  28. package/lib/exceljs.nodejs.js +14 -0
  29. package/lib/stream/xlsx/hyperlink-reader.js +83 -0
  30. package/lib/stream/xlsx/sheet-comments-writer.js +121 -0
  31. package/lib/stream/xlsx/sheet-rels-writer.js +119 -0
  32. package/lib/stream/xlsx/workbook-reader.js +337 -0
  33. package/lib/stream/xlsx/workbook-writer.js +347 -0
  34. package/lib/stream/xlsx/worksheet-reader.js +374 -0
  35. package/lib/stream/xlsx/worksheet-writer.js +717 -0
  36. package/lib/utils/auto-drain.js +15 -0
  37. package/lib/utils/browser-buffer-decode.js +14 -0
  38. package/lib/utils/browser-buffer-encode.js +15 -0
  39. package/lib/utils/cell-matrix.js +165 -0
  40. package/lib/utils/col-cache.js +287 -0
  41. package/lib/utils/copy-style.js +43 -0
  42. package/lib/utils/encryptor.js +55 -0
  43. package/lib/utils/iterate-stream.js +48 -0
  44. package/lib/utils/parse-sax.js +30 -0
  45. package/lib/utils/shared-formula.js +44 -0
  46. package/lib/utils/shared-strings.js +35 -0
  47. package/lib/utils/stream-base64.js +72 -0
  48. package/lib/utils/stream-buf.js +364 -0
  49. package/lib/utils/string-buf.js +82 -0
  50. package/lib/utils/string-builder.js +35 -0
  51. package/lib/utils/stuttered-pipe.js +67 -0
  52. package/lib/utils/typed-stack.js +24 -0
  53. package/lib/utils/under-dash.js +184 -0
  54. package/lib/utils/utils.js +205 -0
  55. package/lib/utils/xml-stream.js +169 -0
  56. package/lib/utils/zip-stream.js +87 -0
  57. package/lib/xlsx/.rels +11 -0
  58. package/lib/xlsx/calcChain.xml +6 -0
  59. package/lib/xlsx/core.xml +7 -0
  60. package/lib/xlsx/defaultnumformats.js +153 -0
  61. package/lib/xlsx/rel-type.js +20 -0
  62. package/lib/xlsx/styles.xml +41 -0
  63. package/lib/xlsx/workbook.xml +16 -0
  64. package/lib/xlsx/xform/base-xform.js +145 -0
  65. package/lib/xlsx/xform/book/defined-name-xform.js +91 -0
  66. package/lib/xlsx/xform/book/sheet-xform.js +34 -0
  67. package/lib/xlsx/xform/book/workbook-calc-properties-xform.js +26 -0
  68. package/lib/xlsx/xform/book/workbook-pivot-cache-xform.js +29 -0
  69. package/lib/xlsx/xform/book/workbook-properties-xform.js +29 -0
  70. package/lib/xlsx/xform/book/workbook-view-xform.js +53 -0
  71. package/lib/xlsx/xform/book/workbook-xform.js +259 -0
  72. package/lib/xlsx/xform/comment/comment-xform.js +105 -0
  73. package/lib/xlsx/xform/comment/comments-xform.js +82 -0
  74. package/lib/xlsx/xform/comment/style/vml-position-xform.js +39 -0
  75. package/lib/xlsx/xform/comment/style/vml-protection-xform.js +36 -0
  76. package/lib/xlsx/xform/comment/vml-anchor-xform.js +60 -0
  77. package/lib/xlsx/xform/comment/vml-client-data-xform.js +95 -0
  78. package/lib/xlsx/xform/comment/vml-notes-xform.js +107 -0
  79. package/lib/xlsx/xform/comment/vml-shape-xform.js +95 -0
  80. package/lib/xlsx/xform/comment/vml-textbox-xform.js +64 -0
  81. package/lib/xlsx/xform/composite-xform.js +56 -0
  82. package/lib/xlsx/xform/core/app-heading-pairs-xform.js +32 -0
  83. package/lib/xlsx/xform/core/app-titles-of-parts-xform.js +28 -0
  84. package/lib/xlsx/xform/core/app-xform.js +100 -0
  85. package/lib/xlsx/xform/core/content-types-xform.js +135 -0
  86. package/lib/xlsx/xform/core/core-xform.js +136 -0
  87. package/lib/xlsx/xform/core/relationship-xform.js +25 -0
  88. package/lib/xlsx/xform/core/relationships-xform.js +73 -0
  89. package/lib/xlsx/xform/drawing/base-cell-anchor-xform.js +48 -0
  90. package/lib/xlsx/xform/drawing/blip-fill-xform.js +71 -0
  91. package/lib/xlsx/xform/drawing/blip-xform.js +42 -0
  92. package/lib/xlsx/xform/drawing/c-nv-pic-pr-xform.js +38 -0
  93. package/lib/xlsx/xform/drawing/c-nv-pr-xform.js +68 -0
  94. package/lib/xlsx/xform/drawing/cell-position-xform.js +77 -0
  95. package/lib/xlsx/xform/drawing/drawing-xform.js +109 -0
  96. package/lib/xlsx/xform/drawing/ext-lst-xform.js +43 -0
  97. package/lib/xlsx/xform/drawing/ext-xform.js +44 -0
  98. package/lib/xlsx/xform/drawing/hlink-click-xform.js +41 -0
  99. package/lib/xlsx/xform/drawing/nv-pic-pr-xform.js +65 -0
  100. package/lib/xlsx/xform/drawing/one-cell-anchor-xform.js +63 -0
  101. package/lib/xlsx/xform/drawing/pic-xform.js +77 -0
  102. package/lib/xlsx/xform/drawing/sp-pr.js +17 -0
  103. package/lib/xlsx/xform/drawing/two-cell-anchor-xform.js +62 -0
  104. package/lib/xlsx/xform/list-xform.js +95 -0
  105. package/lib/xlsx/xform/pivot-table/cache-field.js +43 -0
  106. package/lib/xlsx/xform/pivot-table/pivot-cache-definition-xform.js +77 -0
  107. package/lib/xlsx/xform/pivot-table/pivot-cache-records-xform.js +103 -0
  108. package/lib/xlsx/xform/pivot-table/pivot-table-xform.js +189 -0
  109. package/lib/xlsx/xform/sheet/auto-filter-xform.js +38 -0
  110. package/lib/xlsx/xform/sheet/cell-xform.js +498 -0
  111. package/lib/xlsx/xform/sheet/cf/cf-rule-xform.js +301 -0
  112. package/lib/xlsx/xform/sheet/cf/cfvo-xform.js +27 -0
  113. package/lib/xlsx/xform/sheet/cf/color-scale-xform.js +45 -0
  114. package/lib/xlsx/xform/sheet/cf/conditional-formatting-xform.js +48 -0
  115. package/lib/xlsx/xform/sheet/cf/conditional-formattings-xform.js +92 -0
  116. package/lib/xlsx/xform/sheet/cf/databar-xform.js +49 -0
  117. package/lib/xlsx/xform/sheet/cf/ext-lst-ref-xform.js +87 -0
  118. package/lib/xlsx/xform/sheet/cf/formula-xform.js +25 -0
  119. package/lib/xlsx/xform/sheet/cf/icon-set-xform.js +47 -0
  120. package/lib/xlsx/xform/sheet/cf-ext/cf-icon-ext-xform.js +27 -0
  121. package/lib/xlsx/xform/sheet/cf-ext/cf-rule-ext-xform.js +98 -0
  122. package/lib/xlsx/xform/sheet/cf-ext/cfvo-ext-xform.js +43 -0
  123. package/lib/xlsx/xform/sheet/cf-ext/conditional-formatting-ext-xform.js +62 -0
  124. package/lib/xlsx/xform/sheet/cf-ext/conditional-formattings-ext-xform.js +50 -0
  125. package/lib/xlsx/xform/sheet/cf-ext/databar-ext-xform.js +98 -0
  126. package/lib/xlsx/xform/sheet/cf-ext/f-ext-xform.js +25 -0
  127. package/lib/xlsx/xform/sheet/cf-ext/icon-set-ext-xform.js +73 -0
  128. package/lib/xlsx/xform/sheet/cf-ext/sqref-ext-xform.js +25 -0
  129. package/lib/xlsx/xform/sheet/col-xform.js +86 -0
  130. package/lib/xlsx/xform/sheet/data-validations-xform.js +257 -0
  131. package/lib/xlsx/xform/sheet/dimension-xform.js +29 -0
  132. package/lib/xlsx/xform/sheet/drawing-xform.js +33 -0
  133. package/lib/xlsx/xform/sheet/ext-lst-xform.js +86 -0
  134. package/lib/xlsx/xform/sheet/header-footer-xform.js +146 -0
  135. package/lib/xlsx/xform/sheet/hyperlink-xform.js +54 -0
  136. package/lib/xlsx/xform/sheet/merge-cell-xform.js +27 -0
  137. package/lib/xlsx/xform/sheet/merges.js +56 -0
  138. package/lib/xlsx/xform/sheet/outline-properties-xform.js +43 -0
  139. package/lib/xlsx/xform/sheet/page-breaks-xform.js +27 -0
  140. package/lib/xlsx/xform/sheet/page-margins-xform.js +49 -0
  141. package/lib/xlsx/xform/sheet/page-setup-properties-xform.js +35 -0
  142. package/lib/xlsx/xform/sheet/page-setup-xform.js +103 -0
  143. package/lib/xlsx/xform/sheet/picture-xform.js +33 -0
  144. package/lib/xlsx/xform/sheet/print-options-xform.js +49 -0
  145. package/lib/xlsx/xform/sheet/row-breaks-xform.js +39 -0
  146. package/lib/xlsx/xform/sheet/row-xform.js +142 -0
  147. package/lib/xlsx/xform/sheet/sheet-format-properties-xform.js +55 -0
  148. package/lib/xlsx/xform/sheet/sheet-properties-xform.js +90 -0
  149. package/lib/xlsx/xform/sheet/sheet-protection-xform.js +89 -0
  150. package/lib/xlsx/xform/sheet/sheet-view-xform.js +202 -0
  151. package/lib/xlsx/xform/sheet/table-part-xform.js +33 -0
  152. package/lib/xlsx/xform/sheet/worksheet-xform.js +548 -0
  153. package/lib/xlsx/xform/simple/boolean-xform.js +31 -0
  154. package/lib/xlsx/xform/simple/date-xform.js +66 -0
  155. package/lib/xlsx/xform/simple/float-xform.js +51 -0
  156. package/lib/xlsx/xform/simple/integer-xform.js +57 -0
  157. package/lib/xlsx/xform/simple/string-xform.js +51 -0
  158. package/lib/xlsx/xform/static-xform.js +64 -0
  159. package/lib/xlsx/xform/strings/phonetic-text-xform.js +98 -0
  160. package/lib/xlsx/xform/strings/rich-text-xform.js +101 -0
  161. package/lib/xlsx/xform/strings/shared-string-xform.js +102 -0
  162. package/lib/xlsx/xform/strings/shared-strings-xform.js +127 -0
  163. package/lib/xlsx/xform/strings/text-xform.js +44 -0
  164. package/lib/xlsx/xform/style/alignment-xform.js +172 -0
  165. package/lib/xlsx/xform/style/border-xform.js +207 -0
  166. package/lib/xlsx/xform/style/color-xform.js +63 -0
  167. package/lib/xlsx/xform/style/dxf-xform.js +111 -0
  168. package/lib/xlsx/xform/style/fill-xform.js +364 -0
  169. package/lib/xlsx/xform/style/font-xform.js +102 -0
  170. package/lib/xlsx/xform/style/numfmt-xform.js +63 -0
  171. package/lib/xlsx/xform/style/protection-xform.js +60 -0
  172. package/lib/xlsx/xform/style/style-xform.js +125 -0
  173. package/lib/xlsx/xform/style/styles-xform.js +527 -0
  174. package/lib/xlsx/xform/style/underline-xform.js +47 -0
  175. package/lib/xlsx/xform/table/auto-filter-xform.js +81 -0
  176. package/lib/xlsx/xform/table/custom-filter-xform.js +33 -0
  177. package/lib/xlsx/xform/table/filter-column-xform.js +96 -0
  178. package/lib/xlsx/xform/table/filter-xform.js +31 -0
  179. package/lib/xlsx/xform/table/table-column-xform.js +44 -0
  180. package/lib/xlsx/xform/table/table-style-info-xform.js +41 -0
  181. package/lib/xlsx/xform/table/table-xform.js +131 -0
  182. package/lib/xlsx/xlsx.js +774 -0
  183. package/lib/xlsx/xml/theme1.js +3 -0
  184. package/lib/xlsx/xml/theme1.xml +318 -0
  185. package/package.json +149 -0
@@ -0,0 +1,548 @@
1
+ const _ = require('../../../utils/under-dash');
2
+
3
+ const colCache = require('../../../utils/col-cache');
4
+ const XmlStream = require('../../../utils/xml-stream');
5
+
6
+ const RelType = require('../../rel-type');
7
+
8
+ const Merges = require('./merges');
9
+
10
+ const BaseXform = require('../base-xform');
11
+ const ListXform = require('../list-xform');
12
+ const RowXform = require('./row-xform');
13
+ const ColXform = require('./col-xform');
14
+ const DimensionXform = require('./dimension-xform');
15
+ const HyperlinkXform = require('./hyperlink-xform');
16
+ const MergeCellXform = require('./merge-cell-xform');
17
+ const DataValidationsXform = require('./data-validations-xform');
18
+ const SheetPropertiesXform = require('./sheet-properties-xform');
19
+ const SheetFormatPropertiesXform = require('./sheet-format-properties-xform');
20
+ const SheetViewXform = require('./sheet-view-xform');
21
+ const SheetProtectionXform = require('./sheet-protection-xform');
22
+ const PageMarginsXform = require('./page-margins-xform');
23
+ const PageSetupXform = require('./page-setup-xform');
24
+ const PrintOptionsXform = require('./print-options-xform');
25
+ const AutoFilterXform = require('./auto-filter-xform');
26
+ const PictureXform = require('./picture-xform');
27
+ const DrawingXform = require('./drawing-xform');
28
+ const TablePartXform = require('./table-part-xform');
29
+ const RowBreaksXform = require('./row-breaks-xform');
30
+ const HeaderFooterXform = require('./header-footer-xform');
31
+ const ConditionalFormattingsXform = require('./cf/conditional-formattings-xform');
32
+ const ExtListXform = require('./ext-lst-xform');
33
+
34
+ const mergeRule = (rule, extRule) => {
35
+ Object.keys(extRule).forEach(key => {
36
+ const value = rule[key];
37
+ const extValue = extRule[key];
38
+ if (value === undefined && extValue !== undefined) {
39
+ rule[key] = extValue;
40
+ }
41
+ });
42
+ };
43
+
44
+ const mergeConditionalFormattings = (model, extModel) => {
45
+ // conditional formattings are rendered in worksheet.conditionalFormatting and also in
46
+ // worksheet.extLst.ext.x14:conditionalFormattings
47
+ // some (e.g. dataBar) are even spread across both!
48
+ if (!extModel || !extModel.length) {
49
+ return model;
50
+ }
51
+ if (!model || !model.length) {
52
+ return extModel;
53
+ }
54
+
55
+ // index model rules by x14Id
56
+ const cfMap = {};
57
+ const ruleMap = {};
58
+ model.forEach(cf => {
59
+ cfMap[cf.ref] = cf;
60
+ cf.rules.forEach(rule => {
61
+ const {x14Id} = rule;
62
+ if (x14Id) {
63
+ ruleMap[x14Id] = rule;
64
+ }
65
+ });
66
+ });
67
+
68
+ extModel.forEach(extCf => {
69
+ extCf.rules.forEach(extRule => {
70
+ const rule = ruleMap[extRule.x14Id];
71
+ if (rule) {
72
+ // merge with matching rule
73
+ mergeRule(rule, extRule);
74
+ } else if (cfMap[extCf.ref]) {
75
+ // reuse existing cf ref
76
+ cfMap[extCf.ref].rules.push(extRule);
77
+ } else {
78
+ // create new cf
79
+ model.push({
80
+ ref: extCf.ref,
81
+ rules: [extRule],
82
+ });
83
+ }
84
+ });
85
+ });
86
+
87
+ // need to cope with rules in extModel that don't exist in model
88
+ return model;
89
+ };
90
+
91
+ class WorkSheetXform extends BaseXform {
92
+ constructor(options) {
93
+ super();
94
+
95
+ const {maxRows, maxCols, ignoreNodes} = options || {};
96
+
97
+ this.ignoreNodes = ignoreNodes || [];
98
+
99
+ this.map = {
100
+ sheetPr: new SheetPropertiesXform(),
101
+ dimension: new DimensionXform(),
102
+ sheetViews: new ListXform({
103
+ tag: 'sheetViews',
104
+ count: false,
105
+ childXform: new SheetViewXform(),
106
+ }),
107
+ sheetFormatPr: new SheetFormatPropertiesXform(),
108
+ cols: new ListXform({tag: 'cols', count: false, childXform: new ColXform()}),
109
+ sheetData: new ListXform({
110
+ tag: 'sheetData',
111
+ count: false,
112
+ empty: true,
113
+ childXform: new RowXform({maxItems: maxCols}),
114
+ maxItems: maxRows,
115
+ }),
116
+ autoFilter: new AutoFilterXform(),
117
+ mergeCells: new ListXform({tag: 'mergeCells', count: true, childXform: new MergeCellXform()}),
118
+ rowBreaks: new RowBreaksXform(),
119
+ hyperlinks: new ListXform({
120
+ tag: 'hyperlinks',
121
+ count: false,
122
+ childXform: new HyperlinkXform(),
123
+ }),
124
+ pageMargins: new PageMarginsXform(),
125
+ dataValidations: new DataValidationsXform(),
126
+ pageSetup: new PageSetupXform(),
127
+ headerFooter: new HeaderFooterXform(),
128
+ printOptions: new PrintOptionsXform(),
129
+ picture: new PictureXform(),
130
+ drawing: new DrawingXform(),
131
+ sheetProtection: new SheetProtectionXform(),
132
+ tableParts: new ListXform({tag: 'tableParts', count: true, childXform: new TablePartXform()}),
133
+ conditionalFormatting: new ConditionalFormattingsXform(),
134
+ extLst: new ExtListXform(),
135
+ };
136
+ }
137
+
138
+ prepare(model, options) {
139
+ options.merges = new Merges();
140
+ model.hyperlinks = options.hyperlinks = [];
141
+ model.comments = options.comments = [];
142
+
143
+ options.formulae = {};
144
+ options.siFormulae = 0;
145
+ this.map.cols.prepare(model.cols, options);
146
+ this.map.sheetData.prepare(model.rows, options);
147
+ this.map.conditionalFormatting.prepare(model.conditionalFormattings, options);
148
+
149
+ model.mergeCells = options.merges.mergeCells;
150
+
151
+ // prepare relationships
152
+ const rels = (model.rels = []);
153
+
154
+ function nextRid(r) {
155
+ return `rId${r.length + 1}`;
156
+ }
157
+
158
+ model.hyperlinks.forEach(hyperlink => {
159
+ const rId = nextRid(rels);
160
+ hyperlink.rId = rId;
161
+ rels.push({
162
+ Id: rId,
163
+ Type: RelType.Hyperlink,
164
+ Target: hyperlink.target,
165
+ TargetMode: 'External',
166
+ });
167
+ });
168
+
169
+ // prepare comment relationships
170
+ if (model.comments.length > 0) {
171
+ const comment = {
172
+ Id: nextRid(rels),
173
+ Type: RelType.Comments,
174
+ Target: `../comments${model.id}.xml`,
175
+ };
176
+ rels.push(comment);
177
+ const vmlDrawing = {
178
+ Id: nextRid(rels),
179
+ Type: RelType.VmlDrawing,
180
+ Target: `../drawings/vmlDrawing${model.id}.vml`,
181
+ };
182
+ rels.push(vmlDrawing);
183
+
184
+ model.comments.forEach(item => {
185
+ item.refAddress = colCache.decodeAddress(item.ref);
186
+ });
187
+
188
+ options.commentRefs.push({
189
+ commentName: `comments${model.id}`,
190
+ vmlDrawing: `vmlDrawing${model.id}`,
191
+ });
192
+ }
193
+
194
+ const drawingRelsHash = [];
195
+ let bookImage;
196
+ model.media.forEach(medium => {
197
+ if (medium.type === 'background') {
198
+ const rId = nextRid(rels);
199
+ bookImage = options.media[medium.imageId];
200
+ rels.push({
201
+ Id: rId,
202
+ Type: RelType.Image,
203
+ Target: `../media/${bookImage.name}.${bookImage.extension}`,
204
+ });
205
+ model.background = {
206
+ rId,
207
+ };
208
+ model.image = options.media[medium.imageId];
209
+ } else if (medium.type === 'image') {
210
+ let {drawing} = model;
211
+ bookImage = options.media[medium.imageId];
212
+ if (!drawing) {
213
+ drawing = model.drawing = {
214
+ rId: nextRid(rels),
215
+ name: `drawing${++options.drawingsCount}`,
216
+ anchors: [],
217
+ rels: [],
218
+ };
219
+ options.drawings.push(drawing);
220
+ rels.push({
221
+ Id: drawing.rId,
222
+ Type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing',
223
+ Target: `../drawings/${drawing.name}.xml`,
224
+ });
225
+ }
226
+ let rIdImage =
227
+ this.preImageId === medium.imageId ? drawingRelsHash[medium.imageId] : drawingRelsHash[drawing.rels.length];
228
+ if (!rIdImage) {
229
+ rIdImage = nextRid(drawing.rels);
230
+ drawingRelsHash[drawing.rels.length] = rIdImage;
231
+ drawing.rels.push({
232
+ Id: rIdImage,
233
+ Type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
234
+ Target: `../media/${bookImage.name}.${bookImage.extension}`,
235
+ });
236
+ }
237
+
238
+ const anchor = {
239
+ picture: {
240
+ rId: rIdImage,
241
+ },
242
+ range: medium.range,
243
+ };
244
+ if (medium.hyperlinks && medium.hyperlinks.hyperlink) {
245
+ const rIdHyperLink = nextRid(drawing.rels);
246
+ drawingRelsHash[drawing.rels.length] = rIdHyperLink;
247
+ anchor.picture.hyperlinks = {
248
+ tooltip: medium.hyperlinks.tooltip,
249
+ rId: rIdHyperLink,
250
+ };
251
+ drawing.rels.push({
252
+ Id: rIdHyperLink,
253
+ Type: RelType.Hyperlink,
254
+ Target: medium.hyperlinks.hyperlink,
255
+ TargetMode: 'External',
256
+ });
257
+ }
258
+ this.preImageId = medium.imageId;
259
+ drawing.anchors.push(anchor);
260
+ }
261
+ });
262
+
263
+ // prepare tables
264
+ model.tables.forEach(table => {
265
+ // relationships
266
+ const rId = nextRid(rels);
267
+ table.rId = rId;
268
+ rels.push({
269
+ Id: rId,
270
+ Type: RelType.Table,
271
+ Target: `../tables/${table.target}`,
272
+ });
273
+
274
+ // dynamic styles
275
+ table.columns.forEach(column => {
276
+ const {style} = column;
277
+ if (style) {
278
+ column.dxfId = options.styles.addDxfStyle(style);
279
+ }
280
+ });
281
+ });
282
+
283
+ // prepare pivot tables
284
+ if ((model.pivotTables || []).length) {
285
+ rels.push({
286
+ Id: nextRid(rels),
287
+ Type: RelType.PivotTable,
288
+ Target: '../pivotTables/pivotTable1.xml',
289
+ });
290
+ }
291
+
292
+ // prepare ext items
293
+ this.map.extLst.prepare(model, options);
294
+ }
295
+
296
+ render(xmlStream, model) {
297
+ xmlStream.openXml(XmlStream.StdDocAttributes);
298
+ xmlStream.openNode('worksheet', WorkSheetXform.WORKSHEET_ATTRIBUTES);
299
+
300
+ const sheetFormatPropertiesModel = model.properties
301
+ ? {
302
+ defaultRowHeight: model.properties.defaultRowHeight,
303
+ dyDescent: model.properties.dyDescent,
304
+ outlineLevelCol: model.properties.outlineLevelCol,
305
+ outlineLevelRow: model.properties.outlineLevelRow,
306
+ }
307
+ : undefined;
308
+ if (model.properties && model.properties.defaultColWidth) {
309
+ sheetFormatPropertiesModel.defaultColWidth = model.properties.defaultColWidth;
310
+ }
311
+ const sheetPropertiesModel = {
312
+ outlineProperties: model.properties && model.properties.outlineProperties,
313
+ tabColor: model.properties && model.properties.tabColor,
314
+ pageSetup:
315
+ model.pageSetup && model.pageSetup.fitToPage
316
+ ? {
317
+ fitToPage: model.pageSetup.fitToPage,
318
+ }
319
+ : undefined,
320
+ };
321
+ const pageMarginsModel = model.pageSetup && model.pageSetup.margins;
322
+ const printOptionsModel = {
323
+ showRowColHeaders: model.pageSetup && model.pageSetup.showRowColHeaders,
324
+ showGridLines: model.pageSetup && model.pageSetup.showGridLines,
325
+ horizontalCentered: model.pageSetup && model.pageSetup.horizontalCentered,
326
+ verticalCentered: model.pageSetup && model.pageSetup.verticalCentered,
327
+ };
328
+ const sheetProtectionModel = model.sheetProtection;
329
+
330
+ this.map.sheetPr.render(xmlStream, sheetPropertiesModel);
331
+ this.map.dimension.render(xmlStream, model.dimensions);
332
+ this.map.sheetViews.render(xmlStream, model.views);
333
+ this.map.sheetFormatPr.render(xmlStream, sheetFormatPropertiesModel);
334
+ this.map.cols.render(xmlStream, model.cols);
335
+ this.map.sheetData.render(xmlStream, model.rows);
336
+ this.map.sheetProtection.render(xmlStream, sheetProtectionModel); // Note: must be after sheetData and before autoFilter
337
+ this.map.autoFilter.render(xmlStream, model.autoFilter);
338
+ this.map.mergeCells.render(xmlStream, model.mergeCells);
339
+ this.map.conditionalFormatting.render(xmlStream, model.conditionalFormattings); // Note: must be before dataValidations
340
+ this.map.dataValidations.render(xmlStream, model.dataValidations);
341
+
342
+ // For some reason hyperlinks have to be after the data validations
343
+ this.map.hyperlinks.render(xmlStream, model.hyperlinks);
344
+
345
+ this.map.printOptions.render(xmlStream, printOptionsModel); // Note: must be before pageMargins
346
+ this.map.pageMargins.render(xmlStream, pageMarginsModel);
347
+ this.map.pageSetup.render(xmlStream, model.pageSetup);
348
+ this.map.headerFooter.render(xmlStream, model.headerFooter);
349
+ this.map.rowBreaks.render(xmlStream, model.rowBreaks);
350
+ this.map.drawing.render(xmlStream, model.drawing); // Note: must be after rowBreaks
351
+ this.map.picture.render(xmlStream, model.background); // Note: must be after drawing
352
+ this.map.tableParts.render(xmlStream, model.tables);
353
+
354
+ this.map.extLst.render(xmlStream, model);
355
+
356
+ if (model.rels) {
357
+ // add a <legacyDrawing /> node for each comment
358
+ model.rels.forEach(rel => {
359
+ if (rel.Type === RelType.VmlDrawing) {
360
+ xmlStream.leafNode('legacyDrawing', {'r:id': rel.Id});
361
+ }
362
+ });
363
+ }
364
+
365
+ xmlStream.closeNode();
366
+ }
367
+
368
+ parseOpen(node) {
369
+ if (this.parser) {
370
+ this.parser.parseOpen(node);
371
+ return true;
372
+ }
373
+
374
+ if (node.name === 'worksheet') {
375
+ _.each(this.map, xform => {
376
+ xform.reset();
377
+ });
378
+ return true;
379
+ }
380
+
381
+ if (this.map[node.name] && !this.ignoreNodes.includes(node.name)) {
382
+ this.parser = this.map[node.name];
383
+ this.parser.parseOpen(node);
384
+ }
385
+ return true;
386
+ }
387
+
388
+ parseText(text) {
389
+ if (this.parser) {
390
+ this.parser.parseText(text);
391
+ }
392
+ }
393
+
394
+ parseClose(name) {
395
+ if (this.parser) {
396
+ if (!this.parser.parseClose(name)) {
397
+ this.parser = undefined;
398
+ }
399
+ return true;
400
+ }
401
+ switch (name) {
402
+ case 'worksheet': {
403
+ const properties = this.map.sheetFormatPr.model || {};
404
+ if (this.map.sheetPr.model && this.map.sheetPr.model.tabColor) {
405
+ properties.tabColor = this.map.sheetPr.model.tabColor;
406
+ }
407
+ if (this.map.sheetPr.model && this.map.sheetPr.model.outlineProperties) {
408
+ properties.outlineProperties = this.map.sheetPr.model.outlineProperties;
409
+ }
410
+ const sheetProperties = {
411
+ fitToPage:
412
+ (this.map.sheetPr.model &&
413
+ this.map.sheetPr.model.pageSetup &&
414
+ this.map.sheetPr.model.pageSetup.fitToPage) ||
415
+ false,
416
+ margins: this.map.pageMargins.model,
417
+ };
418
+ const pageSetup = Object.assign(sheetProperties, this.map.pageSetup.model, this.map.printOptions.model);
419
+ const conditionalFormattings = mergeConditionalFormattings(
420
+ this.map.conditionalFormatting.model,
421
+ this.map.extLst.model && this.map.extLst.model['x14:conditionalFormattings']
422
+ );
423
+ this.model = {
424
+ dimensions: this.map.dimension.model,
425
+ cols: this.map.cols.model,
426
+ rows: this.map.sheetData.model,
427
+ mergeCells: this.map.mergeCells.model,
428
+ hyperlinks: this.map.hyperlinks.model,
429
+ dataValidations: this.map.dataValidations.model,
430
+ properties,
431
+ views: this.map.sheetViews.model,
432
+ pageSetup,
433
+ headerFooter: this.map.headerFooter.model,
434
+ background: this.map.picture.model,
435
+ drawing: this.map.drawing.model,
436
+ tables: this.map.tableParts.model,
437
+ conditionalFormattings,
438
+ };
439
+
440
+ if (this.map.autoFilter.model) {
441
+ this.model.autoFilter = this.map.autoFilter.model;
442
+ }
443
+ if (this.map.sheetProtection.model) {
444
+ this.model.sheetProtection = this.map.sheetProtection.model;
445
+ }
446
+
447
+ return false;
448
+ }
449
+
450
+ default:
451
+ // not quite sure how we get here!
452
+ return true;
453
+ }
454
+ }
455
+
456
+ reconcile(model, options) {
457
+ // options.merges = new Merges();
458
+ // options.merges.reconcile(model.mergeCells, model.rows);
459
+ const rels = (model.relationships || []).reduce((h, rel) => {
460
+ h[rel.Id] = rel;
461
+ if (rel.Type === RelType.Comments) {
462
+ model.comments = options.comments[rel.Target].comments;
463
+ }
464
+ if (rel.Type === RelType.VmlDrawing && model.comments && model.comments.length) {
465
+ const vmlComment = options.vmlDrawings[rel.Target].comments;
466
+ model.comments.forEach((comment, index) => {
467
+ comment.note = Object.assign({}, comment.note, vmlComment[index]);
468
+ });
469
+ }
470
+ return h;
471
+ }, {});
472
+ options.commentsMap = (model.comments || []).reduce((h, comment) => {
473
+ if (comment.ref) {
474
+ h[comment.ref] = comment;
475
+ }
476
+ return h;
477
+ }, {});
478
+ options.hyperlinkMap = (model.hyperlinks || []).reduce((h, hyperlink) => {
479
+ if (hyperlink.rId) {
480
+ h[hyperlink.address] = rels[hyperlink.rId].Target;
481
+ }
482
+ return h;
483
+ }, {});
484
+ options.formulae = {};
485
+
486
+ // compact the rows and cells
487
+ model.rows = (model.rows && model.rows.filter(Boolean)) || [];
488
+ model.rows.forEach(row => {
489
+ row.cells = (row.cells && row.cells.filter(Boolean)) || [];
490
+ });
491
+
492
+ this.map.cols.reconcile(model.cols, options);
493
+ this.map.sheetData.reconcile(model.rows, options);
494
+ this.map.conditionalFormatting.reconcile(model.conditionalFormattings, options);
495
+
496
+ model.media = [];
497
+ if (model.drawing) {
498
+ const drawingRel = rels[model.drawing.rId];
499
+ const match = drawingRel.Target.match(/\/drawings\/([a-zA-Z0-9]+)[.][a-zA-Z]{3,4}$/);
500
+ if (match) {
501
+ const drawingName = match[1];
502
+ const drawing = options.drawings[drawingName];
503
+ drawing.anchors.forEach(anchor => {
504
+ if (anchor.medium) {
505
+ const image = {
506
+ type: 'image',
507
+ imageId: anchor.medium.index,
508
+ range: anchor.range,
509
+ hyperlinks: anchor.picture.hyperlinks,
510
+ };
511
+ model.media.push(image);
512
+ }
513
+ });
514
+ }
515
+ }
516
+
517
+ const backgroundRel = model.background && rels[model.background.rId];
518
+ if (backgroundRel) {
519
+ const target = backgroundRel.Target.split('/media/')[1];
520
+ const imageId = options.mediaIndex && options.mediaIndex[target];
521
+ if (imageId !== undefined) {
522
+ model.media.push({
523
+ type: 'background',
524
+ imageId,
525
+ });
526
+ }
527
+ }
528
+
529
+ model.tables = (model.tables || []).map(tablePart => {
530
+ const rel = rels[tablePart.rId];
531
+ return options.tables[rel.Target];
532
+ });
533
+
534
+ delete model.relationships;
535
+ delete model.hyperlinks;
536
+ delete model.comments;
537
+ }
538
+ }
539
+
540
+ WorkSheetXform.WORKSHEET_ATTRIBUTES = {
541
+ xmlns: 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
542
+ 'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
543
+ 'xmlns:mc': 'http://schemas.openxmlformats.org/markup-compatibility/2006',
544
+ 'mc:Ignorable': 'x14ac',
545
+ 'xmlns:x14ac': 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac',
546
+ };
547
+
548
+ module.exports = WorkSheetXform;
@@ -0,0 +1,31 @@
1
+ const BaseXform = require('../base-xform');
2
+
3
+ class BooleanXform extends BaseXform {
4
+ constructor(options) {
5
+ super();
6
+
7
+ this.tag = options.tag;
8
+ this.attr = options.attr;
9
+ }
10
+
11
+ render(xmlStream, model) {
12
+ if (model) {
13
+ xmlStream.openNode(this.tag);
14
+ xmlStream.closeNode();
15
+ }
16
+ }
17
+
18
+ parseOpen(node) {
19
+ if (node.name === this.tag) {
20
+ this.model = true;
21
+ }
22
+ }
23
+
24
+ parseText() {}
25
+
26
+ parseClose() {
27
+ return false;
28
+ }
29
+ }
30
+
31
+ module.exports = BooleanXform;
@@ -0,0 +1,66 @@
1
+ const BaseXform = require('../base-xform');
2
+
3
+ class DateXform extends BaseXform {
4
+ constructor(options) {
5
+ super();
6
+
7
+ this.tag = options.tag;
8
+ this.attr = options.attr;
9
+ this.attrs = options.attrs;
10
+ this._format =
11
+ options.format ||
12
+ function(dt) {
13
+ try {
14
+ if (Number.isNaN(dt.getTime())) return '';
15
+ return dt.toISOString();
16
+ } catch (e) {
17
+ return '';
18
+ }
19
+ };
20
+ this._parse =
21
+ options.parse ||
22
+ function(str) {
23
+ return new Date(str);
24
+ };
25
+ }
26
+
27
+ render(xmlStream, model) {
28
+ if (model) {
29
+ xmlStream.openNode(this.tag);
30
+ if (this.attrs) {
31
+ xmlStream.addAttributes(this.attrs);
32
+ }
33
+ if (this.attr) {
34
+ xmlStream.addAttribute(this.attr, this._format(model));
35
+ } else {
36
+ xmlStream.writeText(this._format(model));
37
+ }
38
+ xmlStream.closeNode();
39
+ }
40
+ }
41
+
42
+ parseOpen(node) {
43
+ if (node.name === this.tag) {
44
+ if (this.attr) {
45
+ this.model = this._parse(node.attributes[this.attr]);
46
+ } else {
47
+ this.text = [];
48
+ }
49
+ }
50
+ }
51
+
52
+ parseText(text) {
53
+ if (!this.attr) {
54
+ this.text.push(text);
55
+ }
56
+ }
57
+
58
+ parseClose() {
59
+ if (!this.attr) {
60
+ this.model = this._parse(this.text.join(''));
61
+ }
62
+ return false;
63
+ }
64
+ }
65
+
66
+ module.exports = DateXform;
@@ -0,0 +1,51 @@
1
+ const BaseXform = require('../base-xform');
2
+
3
+ class FloatXform extends BaseXform {
4
+ constructor(options) {
5
+ super();
6
+
7
+ this.tag = options.tag;
8
+ this.attr = options.attr;
9
+ this.attrs = options.attrs;
10
+ }
11
+
12
+ render(xmlStream, model) {
13
+ if (model !== undefined) {
14
+ xmlStream.openNode(this.tag);
15
+ if (this.attrs) {
16
+ xmlStream.addAttributes(this.attrs);
17
+ }
18
+ if (this.attr) {
19
+ xmlStream.addAttribute(this.attr, model);
20
+ } else {
21
+ xmlStream.writeText(model);
22
+ }
23
+ xmlStream.closeNode();
24
+ }
25
+ }
26
+
27
+ parseOpen(node) {
28
+ if (node.name === this.tag) {
29
+ if (this.attr) {
30
+ this.model = parseFloat(node.attributes[this.attr]);
31
+ } else {
32
+ this.text = [];
33
+ }
34
+ }
35
+ }
36
+
37
+ parseText(text) {
38
+ if (!this.attr) {
39
+ this.text.push(text);
40
+ }
41
+ }
42
+
43
+ parseClose() {
44
+ if (!this.attr) {
45
+ this.model = parseFloat(this.text.join(''));
46
+ }
47
+ return false;
48
+ }
49
+ }
50
+
51
+ module.exports = FloatXform;