@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,15 @@
1
+ const {EventEmitter} = require('events');
2
+
3
+ // =============================================================================
4
+ // AutoDrain - kind of /dev/null
5
+ class AutoDrain extends EventEmitter {
6
+ write(chunk) {
7
+ this.emit('data', chunk);
8
+ }
9
+
10
+ end() {
11
+ this.emit('end');
12
+ }
13
+ }
14
+
15
+ module.exports = AutoDrain;
@@ -0,0 +1,14 @@
1
+ // eslint-disable-next-line node/no-unsupported-features/node-builtins
2
+ const textDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf-8');
3
+
4
+ function bufferToString(chunk) {
5
+ if (typeof chunk === 'string') {
6
+ return chunk;
7
+ }
8
+ if (textDecoder) {
9
+ return textDecoder.decode(chunk);
10
+ }
11
+ return chunk.toString();
12
+ }
13
+
14
+ exports.bufferToString = bufferToString;
@@ -0,0 +1,15 @@
1
+ // eslint-disable-next-line node/no-unsupported-features/node-builtins
2
+ const textEncoder = typeof TextEncoder === 'undefined' ? null : new TextEncoder('utf-8');
3
+ const {Buffer} = require('buffer');
4
+
5
+ function stringToBuffer(str) {
6
+ if (typeof str !== 'string') {
7
+ return str;
8
+ }
9
+ if (textEncoder) {
10
+ return Buffer.from(textEncoder.encode(str).buffer);
11
+ }
12
+ return Buffer.from(str);
13
+ }
14
+
15
+ exports.stringToBuffer = stringToBuffer;
@@ -0,0 +1,165 @@
1
+ const _ = require('./under-dash');
2
+ const colCache = require('./col-cache');
3
+
4
+ class CellMatrix {
5
+ constructor(template) {
6
+ this.template = template;
7
+ this.sheets = {};
8
+ }
9
+
10
+ addCell(addressStr) {
11
+ this.addCellEx(colCache.decodeEx(addressStr));
12
+ }
13
+
14
+ getCell(addressStr) {
15
+ return this.findCellEx(colCache.decodeEx(addressStr), true);
16
+ }
17
+
18
+ findCell(addressStr) {
19
+ return this.findCellEx(colCache.decodeEx(addressStr), false);
20
+ }
21
+
22
+ findCellAt(sheetName, rowNumber, colNumber) {
23
+ const sheet = this.sheets[sheetName];
24
+ const row = sheet && sheet[rowNumber];
25
+ return row && row[colNumber];
26
+ }
27
+
28
+ addCellEx(address) {
29
+ if (address.top) {
30
+ for (let row = address.top; row <= address.bottom; row++) {
31
+ for (let col = address.left; col <= address.right; col++) {
32
+ this.getCellAt(address.sheetName, row, col);
33
+ }
34
+ }
35
+ } else {
36
+ this.findCellEx(address, true);
37
+ }
38
+ }
39
+
40
+ getCellEx(address) {
41
+ return this.findCellEx(address, true);
42
+ }
43
+
44
+ findCellEx(address, create) {
45
+ const sheet = this.findSheet(address, create);
46
+ const row = this.findSheetRow(sheet, address, create);
47
+ return this.findRowCell(row, address, create);
48
+ }
49
+
50
+ getCellAt(sheetName, rowNumber, colNumber) {
51
+ const sheet = this.sheets[sheetName] || (this.sheets[sheetName] = []);
52
+ const row = sheet[rowNumber] || (sheet[rowNumber] = []);
53
+ const cell =
54
+ row[colNumber] ||
55
+ (row[colNumber] = {
56
+ sheetName,
57
+ address: colCache.n2l(colNumber) + rowNumber,
58
+ row: rowNumber,
59
+ col: colNumber,
60
+ });
61
+ return cell;
62
+ }
63
+
64
+ removeCellEx(address) {
65
+ const sheet = this.findSheet(address);
66
+ if (!sheet) {
67
+ return;
68
+ }
69
+ const row = this.findSheetRow(sheet, address);
70
+ if (!row) {
71
+ return;
72
+ }
73
+ delete row[address.col];
74
+ }
75
+
76
+ forEachInSheet(sheetName, callback) {
77
+ const sheet = this.sheets[sheetName];
78
+ if (sheet) {
79
+ sheet.forEach((row, rowNumber) => {
80
+ if (row) {
81
+ row.forEach((cell, colNumber) => {
82
+ if (cell) {
83
+ callback(cell, rowNumber, colNumber);
84
+ }
85
+ });
86
+ }
87
+ });
88
+ }
89
+ }
90
+
91
+ forEach(callback) {
92
+ _.each(this.sheets, (sheet, sheetName) => {
93
+ this.forEachInSheet(sheetName, callback);
94
+ });
95
+ }
96
+
97
+ map(callback) {
98
+ const results = [];
99
+ this.forEach(cell => {
100
+ results.push(callback(cell));
101
+ });
102
+ return results;
103
+ }
104
+
105
+ findSheet(address, create) {
106
+ const name = address.sheetName;
107
+ if (this.sheets[name]) {
108
+ return this.sheets[name];
109
+ }
110
+ if (create) {
111
+ return (this.sheets[name] = []);
112
+ }
113
+ return undefined;
114
+ }
115
+
116
+ findSheetRow(sheet, address, create) {
117
+ const {row} = address;
118
+ if (sheet && sheet[row]) {
119
+ return sheet[row];
120
+ }
121
+ if (create) {
122
+ return (sheet[row] = []);
123
+ }
124
+ return undefined;
125
+ }
126
+
127
+ findRowCell(row, address, create) {
128
+ const {col} = address;
129
+ if (row && row[col]) {
130
+ return row[col];
131
+ }
132
+ if (create) {
133
+ return (row[col] = this.template
134
+ ? Object.assign(address, JSON.parse(JSON.stringify(this.template)))
135
+ : address);
136
+ }
137
+ return undefined;
138
+ }
139
+
140
+ spliceRows(sheetName, start, numDelete, numInsert) {
141
+ const sheet = this.sheets[sheetName];
142
+ if (sheet) {
143
+ const inserts = [];
144
+ for (let i = 0; i < numInsert; i++) {
145
+ inserts.push([]);
146
+ }
147
+ sheet.splice(start, numDelete, ...inserts);
148
+ }
149
+ }
150
+
151
+ spliceColumns(sheetName, start, numDelete, numInsert) {
152
+ const sheet = this.sheets[sheetName];
153
+ if (sheet) {
154
+ const inserts = [];
155
+ for (let i = 0; i < numInsert; i++) {
156
+ inserts.push(null);
157
+ }
158
+ _.each(sheet, row => {
159
+ row.splice(start, numDelete, ...inserts);
160
+ });
161
+ }
162
+ }
163
+ }
164
+
165
+ module.exports = CellMatrix;
@@ -0,0 +1,287 @@
1
+ const addressRegex = /^[A-Z]+\d+$/;
2
+ // =========================================================================
3
+ // Column Letter to Number conversion
4
+ const colCache = {
5
+ _dictionary: [
6
+ 'A',
7
+ 'B',
8
+ 'C',
9
+ 'D',
10
+ 'E',
11
+ 'F',
12
+ 'G',
13
+ 'H',
14
+ 'I',
15
+ 'J',
16
+ 'K',
17
+ 'L',
18
+ 'M',
19
+ 'N',
20
+ 'O',
21
+ 'P',
22
+ 'Q',
23
+ 'R',
24
+ 'S',
25
+ 'T',
26
+ 'U',
27
+ 'V',
28
+ 'W',
29
+ 'X',
30
+ 'Y',
31
+ 'Z',
32
+ ],
33
+ _l2nFill: 0,
34
+ _l2n: {},
35
+ _n2l: [],
36
+ _level(n) {
37
+ if (n <= 26) {
38
+ return 1;
39
+ }
40
+ if (n <= 26 * 26) {
41
+ return 2;
42
+ }
43
+ return 3;
44
+ },
45
+ _fill(level) {
46
+ let c;
47
+ let v;
48
+ let l1;
49
+ let l2;
50
+ let l3;
51
+ let n = 1;
52
+ if (level >= 4) {
53
+ throw new Error('Out of bounds. Excel supports columns from 1 to 16384');
54
+ }
55
+ if (this._l2nFill < 1 && level >= 1) {
56
+ while (n <= 26) {
57
+ c = this._dictionary[n - 1];
58
+ this._n2l[n] = c;
59
+ this._l2n[c] = n;
60
+ n++;
61
+ }
62
+ this._l2nFill = 1;
63
+ }
64
+ if (this._l2nFill < 2 && level >= 2) {
65
+ n = 27;
66
+ while (n <= 26 + (26 * 26)) {
67
+ v = n - (26 + 1);
68
+ l1 = v % 26;
69
+ l2 = Math.floor(v / 26);
70
+ c = this._dictionary[l2] + this._dictionary[l1];
71
+ this._n2l[n] = c;
72
+ this._l2n[c] = n;
73
+ n++;
74
+ }
75
+ this._l2nFill = 2;
76
+ }
77
+ if (this._l2nFill < 3 && level >= 3) {
78
+ n = 26 + (26 * 26) + 1;
79
+ while (n <= 16384) {
80
+ v = n - ((26 * 26) + 26 + 1);
81
+ l1 = v % 26;
82
+ l2 = Math.floor(v / 26) % 26;
83
+ l3 = Math.floor(v / (26 * 26));
84
+ c = this._dictionary[l3] + this._dictionary[l2] + this._dictionary[l1];
85
+ this._n2l[n] = c;
86
+ this._l2n[c] = n;
87
+ n++;
88
+ }
89
+ this._l2nFill = 3;
90
+ }
91
+ },
92
+ l2n(l) {
93
+ if (!this._l2n[l]) {
94
+ this._fill(l.length);
95
+ }
96
+ if (!this._l2n[l]) {
97
+ throw new Error(`Out of bounds. Invalid column letter: ${l}`);
98
+ }
99
+ return this._l2n[l];
100
+ },
101
+ n2l(n) {
102
+ if (n < 1 || n > 16384) {
103
+ throw new Error(`${n} is out of bounds. Excel supports columns from 1 to 16384`);
104
+ }
105
+ if (!this._n2l[n]) {
106
+ this._fill(this._level(n));
107
+ }
108
+ return this._n2l[n];
109
+ },
110
+
111
+ // =========================================================================
112
+ // Address processing
113
+ _hash: {},
114
+
115
+ // check if value looks like an address
116
+ validateAddress(value) {
117
+ if (!addressRegex.test(value)) {
118
+ throw new Error(`Invalid Address: ${value}`);
119
+ }
120
+ return true;
121
+ },
122
+
123
+ // convert address string into structure
124
+ decodeAddress(value) {
125
+ const addr = value.length < 5 && this._hash[value];
126
+ if (addr) {
127
+ return addr;
128
+ }
129
+ let hasCol = false;
130
+ let col = '';
131
+ let colNumber = 0;
132
+ let hasRow = false;
133
+ let row = '';
134
+ let rowNumber = 0;
135
+ for (let i = 0, char; i < value.length; i++) {
136
+ char = value.charCodeAt(i);
137
+ // col should before row
138
+ if (!hasRow && char >= 65 && char <= 90) {
139
+ // 65 = 'A'.charCodeAt(0)
140
+ // 90 = 'Z'.charCodeAt(0)
141
+ hasCol = true;
142
+ col += value[i];
143
+ // colNumber starts from 1
144
+ colNumber = (colNumber * 26) + char - 64;
145
+ } else if (char >= 48 && char <= 57) {
146
+ // 48 = '0'.charCodeAt(0)
147
+ // 57 = '9'.charCodeAt(0)
148
+ hasRow = true;
149
+ row += value[i];
150
+ // rowNumber starts from 0
151
+ rowNumber = (rowNumber * 10) + char - 48;
152
+ } else if (hasRow && hasCol && char !== 36) {
153
+ // 36 = '$'.charCodeAt(0)
154
+ break;
155
+ }
156
+ }
157
+ if (!hasCol) {
158
+ colNumber = undefined;
159
+ } else if (colNumber > 16384) {
160
+ throw new Error(`Out of bounds. Invalid column letter: ${col}`);
161
+ }
162
+ if (!hasRow) {
163
+ rowNumber = undefined;
164
+ }
165
+
166
+ // in case $row$col
167
+ value = col + row;
168
+
169
+ const address = {
170
+ address: value,
171
+ col: colNumber,
172
+ row: rowNumber,
173
+ $col$row: `$${col}$${row}`,
174
+ };
175
+
176
+ // mem fix - cache only the tl 100x100 square
177
+ if (colNumber <= 100 && rowNumber <= 100) {
178
+ this._hash[value] = address;
179
+ this._hash[address.$col$row] = address;
180
+ }
181
+
182
+ return address;
183
+ },
184
+
185
+ // convert r,c into structure (if only 1 arg, assume r is address string)
186
+ getAddress(r, c) {
187
+ if (c) {
188
+ const address = this.n2l(c) + r;
189
+ return this.decodeAddress(address);
190
+ }
191
+ return this.decodeAddress(r);
192
+ },
193
+
194
+ // convert [address], [tl:br] into address structures
195
+ decode(value) {
196
+ const parts = value.split(':');
197
+ if (parts.length === 2) {
198
+ const tl = this.decodeAddress(parts[0]);
199
+ const br = this.decodeAddress(parts[1]);
200
+ const result = {
201
+ top: Math.min(tl.row, br.row),
202
+ left: Math.min(tl.col, br.col),
203
+ bottom: Math.max(tl.row, br.row),
204
+ right: Math.max(tl.col, br.col),
205
+ };
206
+ // reconstruct tl, br and dimensions
207
+ result.tl = this.n2l(result.left) + result.top;
208
+ result.br = this.n2l(result.right) + result.bottom;
209
+ result.dimensions = `${result.tl}:${result.br}`;
210
+ return result;
211
+ }
212
+ return this.decodeAddress(value);
213
+ },
214
+
215
+ // convert [sheetName!][$]col[$]row[[$]col[$]row] into address or range structures
216
+ decodeEx(value) {
217
+ const groups = value.match(/(?:(?:(?:'((?:[^']|'')*)')|([^'^ !]*))!)?(.*)/);
218
+
219
+ const sheetName = groups[1] || groups[2]; // Qouted and unqouted groups
220
+ const reference = groups[3]; // Remaining address
221
+
222
+ const parts = reference.split(':');
223
+ if (parts.length > 1) {
224
+ let tl = this.decodeAddress(parts[0]);
225
+ let br = this.decodeAddress(parts[1]);
226
+ const top = Math.min(tl.row, br.row);
227
+ const left = Math.min(tl.col, br.col);
228
+ const bottom = Math.max(tl.row, br.row);
229
+ const right = Math.max(tl.col, br.col);
230
+
231
+ tl = this.n2l(left) + top;
232
+ br = this.n2l(right) + bottom;
233
+
234
+ return {
235
+ top,
236
+ left,
237
+ bottom,
238
+ right,
239
+ sheetName,
240
+ tl: {address: tl, col: left, row: top, $col$row: `$${this.n2l(left)}$${top}`, sheetName},
241
+ br: {
242
+ address: br,
243
+ col: right,
244
+ row: bottom,
245
+ $col$row: `$${this.n2l(right)}$${bottom}`,
246
+ sheetName,
247
+ },
248
+ dimensions: `${tl}:${br}`,
249
+ };
250
+ }
251
+ if (reference.startsWith('#')) {
252
+ return sheetName ? {sheetName, error: reference} : {error: reference};
253
+ }
254
+
255
+ const address = this.decodeAddress(reference);
256
+ return sheetName ? {sheetName, ...address} : address;
257
+ },
258
+
259
+ // convert row,col into address string
260
+ encodeAddress(row, col) {
261
+ return colCache.n2l(col) + row;
262
+ },
263
+
264
+ // convert row,col into string address or t,l,b,r into range
265
+ encode() {
266
+ switch (arguments.length) {
267
+ case 2:
268
+ return colCache.encodeAddress(arguments[0], arguments[1]);
269
+ case 4:
270
+ return `${colCache.encodeAddress(arguments[0], arguments[1])}:${colCache.encodeAddress(
271
+ arguments[2],
272
+ arguments[3]
273
+ )}`;
274
+ default:
275
+ throw new Error('Can only encode with 2 or 4 arguments');
276
+ }
277
+ },
278
+
279
+ // return true if address is contained within range
280
+ inRange(range, address) {
281
+ const [left, top, , right, bottom] = range;
282
+ const [col, row] = address;
283
+ return col >= left && col <= right && row >= top && row <= bottom;
284
+ },
285
+ };
286
+
287
+ module.exports = colCache;
@@ -0,0 +1,43 @@
1
+ const oneDepthCopy = (obj, nestKeys) => ({
2
+ ...obj,
3
+ ...nestKeys.reduce((memo, key) => {
4
+ if (obj[key]) memo[key] = {...obj[key]};
5
+ return memo;
6
+ }, {}),
7
+ });
8
+
9
+ const setIfExists = (src, dst, key, nestKeys = []) => {
10
+ if (src[key]) dst[key] = oneDepthCopy(src[key], nestKeys);
11
+ };
12
+
13
+ const isEmptyObj = obj => Object.keys(obj).length === 0;
14
+
15
+ const copyStyle = style => {
16
+ if (!style) return style;
17
+ if (isEmptyObj(style)) return {};
18
+
19
+ const copied = {...style};
20
+
21
+ setIfExists(style, copied, 'font', ['color']);
22
+ setIfExists(style, copied, 'alignment');
23
+ setIfExists(style, copied, 'protection');
24
+ if (style.border) {
25
+ setIfExists(style, copied, 'border');
26
+ setIfExists(style.border, copied.border, 'top', ['color']);
27
+ setIfExists(style.border, copied.border, 'left', ['color']);
28
+ setIfExists(style.border, copied.border, 'bottom', ['color']);
29
+ setIfExists(style.border, copied.border, 'right', ['color']);
30
+ setIfExists(style.border, copied.border, 'diagonal', ['color']);
31
+ }
32
+
33
+ if (style.fill) {
34
+ setIfExists(style, copied, 'fill', ['fgColor', 'bgColor', 'center']);
35
+ if (style.fill.stops) {
36
+ copied.fill.stops = style.fill.stops.map(s => oneDepthCopy(s, ['color']));
37
+ }
38
+ }
39
+
40
+ return copied;
41
+ };
42
+
43
+ exports.copyStyle = copyStyle;
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('crypto');
4
+
5
+ const Encryptor = {
6
+ /**
7
+ * Calculate a hash of the concatenated buffers with the given algorithm.
8
+ * @param {string} algorithm - The hash algorithm.
9
+ * @returns {Buffer} The hash
10
+ */
11
+ hash(algorithm, ...buffers) {
12
+ const hash = crypto.createHash(algorithm);
13
+ hash.update(Buffer.concat(buffers));
14
+ return hash.digest();
15
+ },
16
+ /**
17
+ * Convert a password into an encryption key
18
+ * @param {string} password - The password
19
+ * @param {string} hashAlgorithm - The hash algoritm
20
+ * @param {string} saltValue - The salt value
21
+ * @param {number} spinCount - The spin count
22
+ * @param {number} keyBits - The length of the key in bits
23
+ * @param {Buffer} blockKey - The block key
24
+ * @returns {Buffer} The encryption key
25
+ */
26
+ convertPasswordToHash(password, hashAlgorithm, saltValue, spinCount) {
27
+ hashAlgorithm = hashAlgorithm.toLowerCase();
28
+ const hashes = crypto.getHashes();
29
+ if (hashes.indexOf(hashAlgorithm) < 0) {
30
+ throw new Error(`Hash algorithm '${hashAlgorithm}' not supported!`);
31
+ }
32
+
33
+ // Password must be in unicode buffer
34
+ const passwordBuffer = Buffer.from(password, 'utf16le');
35
+ // Generate the initial hash
36
+ let key = this.hash(hashAlgorithm, Buffer.from(saltValue, 'base64'), passwordBuffer);
37
+ // Now regenerate until spin count
38
+ for (let i = 0; i < spinCount; i++) {
39
+ const iterator = Buffer.alloc(4);
40
+ // this is the 'special' element of Excel password hashing
41
+ // that stops us from using crypto.pbkdf2()
42
+ iterator.writeUInt32LE(i, 0);
43
+ key = this.hash(hashAlgorithm, key, iterator);
44
+ }
45
+ return key.toString('base64');
46
+ },
47
+ /**
48
+ * Generates cryptographically strong pseudo-random data.
49
+ * @param size The size argument is a number indicating the number of bytes to generate.
50
+ */
51
+ randomBytes(size) {
52
+ return crypto.randomBytes(size);
53
+ },
54
+ };
55
+ module.exports = Encryptor;
@@ -0,0 +1,48 @@
1
+ module.exports = async function* iterateStream(stream) {
2
+ const contents = [];
3
+ stream.on('data', data => contents.push(data));
4
+
5
+ let resolveStreamEndedPromise;
6
+ const streamEndedPromise = new Promise(resolve => (resolveStreamEndedPromise = resolve));
7
+
8
+ let ended = false;
9
+ stream.on('end', () => {
10
+ ended = true;
11
+ resolveStreamEndedPromise();
12
+ });
13
+
14
+ let error = false;
15
+ stream.on('error', err => {
16
+ error = err;
17
+ resolveStreamEndedPromise();
18
+ });
19
+
20
+ while (!ended || contents.length > 0) {
21
+ if (contents.length === 0) {
22
+ stream.resume();
23
+ // eslint-disable-next-line no-await-in-loop
24
+ await Promise.race([once(stream, 'data'), streamEndedPromise]);
25
+ } else {
26
+ stream.pause();
27
+ const data = contents.shift();
28
+ yield data;
29
+ }
30
+ if (error) throw error;
31
+ }
32
+ resolveStreamEndedPromise();
33
+ };
34
+
35
+ function once(eventEmitter, type) {
36
+ // TODO: Use require('events').once when node v10 is dropped
37
+ return new Promise(resolve => {
38
+ let fired = false;
39
+ const handler = () => {
40
+ if (!fired) {
41
+ fired = true;
42
+ eventEmitter.removeListener(type, handler);
43
+ resolve();
44
+ }
45
+ };
46
+ eventEmitter.addListener(type, handler);
47
+ });
48
+ }
@@ -0,0 +1,30 @@
1
+ const {SaxesParser} = require('saxes');
2
+ const {PassThrough} = require('readable-stream');
3
+ const {bufferToString} = require('./browser-buffer-decode');
4
+
5
+ module.exports = async function* (iterable) {
6
+ // TODO: Remove once node v8 is deprecated
7
+ // Detect and upgrade old streams
8
+ if (iterable.pipe && !iterable[Symbol.asyncIterator]) {
9
+ iterable = iterable.pipe(new PassThrough());
10
+ }
11
+ const saxesParser = new SaxesParser();
12
+ let error;
13
+ saxesParser.on('error', err => {
14
+ error = err;
15
+ });
16
+ let events = [];
17
+ saxesParser.on('opentag', value => events.push({eventType: 'opentag', value}));
18
+ saxesParser.on('text', value => events.push({eventType: 'text', value}));
19
+ saxesParser.on('closetag', value => events.push({eventType: 'closetag', value}));
20
+ for await (const chunk of iterable) {
21
+ saxesParser.write(bufferToString(chunk));
22
+ // saxesParser.write and saxesParser.on() are synchronous,
23
+ // so we can only reach the below line once all events have been emitted
24
+ if (error) throw error;
25
+ // As a performance optimization, we gather all events instead of passing
26
+ // them one by one, which would cause each event to go through the event queue
27
+ yield events;
28
+ events = [];
29
+ }
30
+ };