You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					509 lines
				
				14 KiB
			
		
		
			
		
	
	
					509 lines
				
				14 KiB
			| 
											2 years ago
										 | "use strict"; | ||
|  | 
 | ||
|  | function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } | ||
|  | 
 | ||
|  | function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } | ||
|  | 
 | ||
|  | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
|  | 
 | ||
|  | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } | ||
|  | 
 | ||
|  | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } | ||
|  | 
 | ||
|  | var fs = require('fs'); | ||
|  | 
 | ||
|  | var Archiver = require('archiver'); | ||
|  | 
 | ||
|  | var StreamBuf = require('../../utils/stream-buf'); | ||
|  | 
 | ||
|  | var RelType = require('../../xlsx/rel-type'); | ||
|  | 
 | ||
|  | var StylesXform = require('../../xlsx/xform/style/styles-xform'); | ||
|  | 
 | ||
|  | var SharedStrings = require('../../utils/shared-strings'); | ||
|  | 
 | ||
|  | var DefinedNames = require('../../doc/defined-names'); | ||
|  | 
 | ||
|  | var CoreXform = require('../../xlsx/xform/core/core-xform'); | ||
|  | 
 | ||
|  | var RelationshipsXform = require('../../xlsx/xform/core/relationships-xform'); | ||
|  | 
 | ||
|  | var ContentTypesXform = require('../../xlsx/xform/core/content-types-xform'); | ||
|  | 
 | ||
|  | var AppXform = require('../../xlsx/xform/core/app-xform'); | ||
|  | 
 | ||
|  | var WorkbookXform = require('../../xlsx/xform/book/workbook-xform'); | ||
|  | 
 | ||
|  | var SharedStringsXform = require('../../xlsx/xform/strings/shared-strings-xform'); | ||
|  | 
 | ||
|  | var WorksheetWriter = require('./worksheet-writer'); | ||
|  | 
 | ||
|  | var theme1Xml = require('../../xlsx/xml/theme1.js'); | ||
|  | 
 | ||
|  | var WorkbookWriter = /*#__PURE__*/function () { | ||
|  |   function WorkbookWriter(options) { | ||
|  |     _classCallCheck(this, WorkbookWriter); | ||
|  | 
 | ||
|  |     options = options || {}; | ||
|  |     this.created = options.created || new Date(); | ||
|  |     this.modified = options.modified || this.created; | ||
|  |     this.creator = options.creator || 'ExcelJS'; | ||
|  |     this.lastModifiedBy = options.lastModifiedBy || 'ExcelJS'; | ||
|  |     this.lastPrinted = options.lastPrinted; // using shared strings creates a smaller xlsx file but may use more memory
 | ||
|  | 
 | ||
|  |     this.useSharedStrings = options.useSharedStrings || false; | ||
|  |     this.sharedStrings = new SharedStrings(); // style manager
 | ||
|  | 
 | ||
|  |     this.styles = options.useStyles ? new StylesXform(true) : new StylesXform.Mock(true); // defined names
 | ||
|  | 
 | ||
|  |     this._definedNames = new DefinedNames(); | ||
|  |     this._worksheets = []; | ||
|  |     this.views = []; | ||
|  |     this.zipOptions = options.zip; | ||
|  |     this.media = []; | ||
|  |     this.commentRefs = []; | ||
|  |     this.zip = Archiver('zip', this.zipOptions); | ||
|  | 
 | ||
|  |     if (options.stream) { | ||
|  |       this.stream = options.stream; | ||
|  |     } else if (options.filename) { | ||
|  |       this.stream = fs.createWriteStream(options.filename); | ||
|  |     } else { | ||
|  |       this.stream = new StreamBuf(); | ||
|  |     } | ||
|  | 
 | ||
|  |     this.zip.pipe(this.stream); // these bits can be added right now
 | ||
|  | 
 | ||
|  |     this.promise = Promise.all([this.addThemes(), this.addOfficeRels()]); | ||
|  |   } | ||
|  | 
 | ||
|  |   _createClass(WorkbookWriter, [{ | ||
|  |     key: "_openStream", | ||
|  |     value: function _openStream(path) { | ||
|  |       var stream = new StreamBuf({ | ||
|  |         bufSize: 65536, | ||
|  |         batch: true | ||
|  |       }); | ||
|  |       this.zip.append(stream, { | ||
|  |         name: path | ||
|  |       }); | ||
|  |       stream.on('finish', function () { | ||
|  |         stream.emit('zipped'); | ||
|  |       }); | ||
|  |       return stream; | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "_commitWorksheets", | ||
|  |     value: function _commitWorksheets() { | ||
|  |       var commitWorksheet = function commitWorksheet(worksheet) { | ||
|  |         if (!worksheet.committed) { | ||
|  |           return new Promise(function (resolve) { | ||
|  |             worksheet.stream.on('zipped', function () { | ||
|  |               resolve(); | ||
|  |             }); | ||
|  |             worksheet.commit(); | ||
|  |           }); | ||
|  |         } | ||
|  | 
 | ||
|  |         return Promise.resolve(); | ||
|  |       }; // if there are any uncommitted worksheets, commit them now and wait
 | ||
|  | 
 | ||
|  | 
 | ||
|  |       var promises = this._worksheets.map(commitWorksheet); | ||
|  | 
 | ||
|  |       if (promises.length) { | ||
|  |         return Promise.all(promises); | ||
|  |       } | ||
|  | 
 | ||
|  |       return Promise.resolve(); | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "commit", | ||
|  |     value: function () { | ||
|  |       var _commit = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() { | ||
|  |         return regeneratorRuntime.wrap(function _callee$(_context) { | ||
|  |           while (1) { | ||
|  |             switch (_context.prev = _context.next) { | ||
|  |               case 0: | ||
|  |                 _context.next = 2; | ||
|  |                 return this.promise; | ||
|  | 
 | ||
|  |               case 2: | ||
|  |                 _context.next = 4; | ||
|  |                 return this.addMedia(); | ||
|  | 
 | ||
|  |               case 4: | ||
|  |                 _context.next = 6; | ||
|  |                 return this._commitWorksheets(); | ||
|  | 
 | ||
|  |               case 6: | ||
|  |                 _context.next = 8; | ||
|  |                 return Promise.all([this.addContentTypes(), this.addApp(), this.addCore(), this.addSharedStrings(), this.addStyles(), this.addWorkbookRels()]); | ||
|  | 
 | ||
|  |               case 8: | ||
|  |                 _context.next = 10; | ||
|  |                 return this.addWorkbook(); | ||
|  | 
 | ||
|  |               case 10: | ||
|  |                 return _context.abrupt("return", this._finalize()); | ||
|  | 
 | ||
|  |               case 11: | ||
|  |               case "end": | ||
|  |                 return _context.stop(); | ||
|  |             } | ||
|  |           } | ||
|  |         }, _callee, this); | ||
|  |       })); | ||
|  | 
 | ||
|  |       function commit() { | ||
|  |         return _commit.apply(this, arguments); | ||
|  |       } | ||
|  | 
 | ||
|  |       return commit; | ||
|  |     }() | ||
|  |   }, { | ||
|  |     key: "addImage", | ||
|  |     value: function addImage(image) { | ||
|  |       var id = this.media.length; | ||
|  |       var medium = Object.assign({}, image, { | ||
|  |         type: 'image', | ||
|  |         name: "image".concat(id, ".").concat(image.extension) | ||
|  |       }); | ||
|  |       this.media.push(medium); | ||
|  |       return id; | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "getImage", | ||
|  |     value: function getImage(id) { | ||
|  |       return this.media[id]; | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "addWorksheet", | ||
|  |     value: function addWorksheet(name, options) { | ||
|  |       // it's possible to add a worksheet with different than default
 | ||
|  |       // shared string handling
 | ||
|  |       // in fact, it's even possible to switch it mid-sheet
 | ||
|  |       options = options || {}; | ||
|  |       var useSharedStrings = options.useSharedStrings !== undefined ? options.useSharedStrings : this.useSharedStrings; | ||
|  | 
 | ||
|  |       if (options.tabColor) { | ||
|  |         // eslint-disable-next-line no-console
 | ||
|  |         console.trace('tabColor option has moved to { properties: tabColor: {...} }'); | ||
|  |         options.properties = Object.assign({ | ||
|  |           tabColor: options.tabColor | ||
|  |         }, options.properties); | ||
|  |       } | ||
|  | 
 | ||
|  |       var id = this.nextId; | ||
|  |       name = name || "sheet".concat(id); | ||
|  |       var worksheet = new WorksheetWriter({ | ||
|  |         id: id, | ||
|  |         name: name, | ||
|  |         workbook: this, | ||
|  |         useSharedStrings: useSharedStrings, | ||
|  |         properties: options.properties, | ||
|  |         state: options.state, | ||
|  |         pageSetup: options.pageSetup, | ||
|  |         views: options.views, | ||
|  |         autoFilter: options.autoFilter, | ||
|  |         headerFooter: options.headerFooter | ||
|  |       }); | ||
|  |       this._worksheets[id] = worksheet; | ||
|  |       return worksheet; | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "getWorksheet", | ||
|  |     value: function getWorksheet(id) { | ||
|  |       if (id === undefined) { | ||
|  |         return this._worksheets.find(function () { | ||
|  |           return true; | ||
|  |         }); | ||
|  |       } | ||
|  | 
 | ||
|  |       if (typeof id === 'number') { | ||
|  |         return this._worksheets[id]; | ||
|  |       } | ||
|  | 
 | ||
|  |       if (typeof id === 'string') { | ||
|  |         return this._worksheets.find(function (worksheet) { | ||
|  |           return worksheet && worksheet.name === id; | ||
|  |         }); | ||
|  |       } | ||
|  | 
 | ||
|  |       return undefined; | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "addStyles", | ||
|  |     value: function addStyles() { | ||
|  |       var _this = this; | ||
|  | 
 | ||
|  |       return new Promise(function (resolve) { | ||
|  |         _this.zip.append(_this.styles.xml, { | ||
|  |           name: 'xl/styles.xml' | ||
|  |         }); | ||
|  | 
 | ||
|  |         resolve(); | ||
|  |       }); | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "addThemes", | ||
|  |     value: function addThemes() { | ||
|  |       var _this2 = this; | ||
|  | 
 | ||
|  |       return new Promise(function (resolve) { | ||
|  |         _this2.zip.append(theme1Xml, { | ||
|  |           name: 'xl/theme/theme1.xml' | ||
|  |         }); | ||
|  | 
 | ||
|  |         resolve(); | ||
|  |       }); | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "addOfficeRels", | ||
|  |     value: function addOfficeRels() { | ||
|  |       var _this3 = this; | ||
|  | 
 | ||
|  |       return new Promise(function (resolve) { | ||
|  |         var xform = new RelationshipsXform(); | ||
|  |         var xml = xform.toXml([{ | ||
|  |           Id: 'rId1', | ||
|  |           Type: RelType.OfficeDocument, | ||
|  |           Target: 'xl/workbook.xml' | ||
|  |         }, { | ||
|  |           Id: 'rId2', | ||
|  |           Type: RelType.CoreProperties, | ||
|  |           Target: 'docProps/core.xml' | ||
|  |         }, { | ||
|  |           Id: 'rId3', | ||
|  |           Type: RelType.ExtenderProperties, | ||
|  |           Target: 'docProps/app.xml' | ||
|  |         }]); | ||
|  | 
 | ||
|  |         _this3.zip.append(xml, { | ||
|  |           name: '/_rels/.rels' | ||
|  |         }); | ||
|  | 
 | ||
|  |         resolve(); | ||
|  |       }); | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "addContentTypes", | ||
|  |     value: function addContentTypes() { | ||
|  |       var _this4 = this; | ||
|  | 
 | ||
|  |       return new Promise(function (resolve) { | ||
|  |         var model = { | ||
|  |           worksheets: _this4._worksheets.filter(Boolean), | ||
|  |           sharedStrings: _this4.sharedStrings, | ||
|  |           commentRefs: _this4.commentRefs, | ||
|  |           media: _this4.media | ||
|  |         }; | ||
|  |         var xform = new ContentTypesXform(); | ||
|  |         var xml = xform.toXml(model); | ||
|  | 
 | ||
|  |         _this4.zip.append(xml, { | ||
|  |           name: '[Content_Types].xml' | ||
|  |         }); | ||
|  | 
 | ||
|  |         resolve(); | ||
|  |       }); | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "addMedia", | ||
|  |     value: function addMedia() { | ||
|  |       var _this5 = this; | ||
|  | 
 | ||
|  |       return Promise.all(this.media.map(function (medium) { | ||
|  |         if (medium.type === 'image') { | ||
|  |           var filename = "xl/media/".concat(medium.name); | ||
|  | 
 | ||
|  |           if (medium.filename) { | ||
|  |             return _this5.zip.file(medium.filename, { | ||
|  |               name: filename | ||
|  |             }); | ||
|  |           } | ||
|  | 
 | ||
|  |           if (medium.buffer) { | ||
|  |             return _this5.zip.append(medium.buffer, { | ||
|  |               name: filename | ||
|  |             }); | ||
|  |           } | ||
|  | 
 | ||
|  |           if (medium.base64) { | ||
|  |             var dataimg64 = medium.base64; | ||
|  |             var content = dataimg64.substring(dataimg64.indexOf(',') + 1); | ||
|  |             return _this5.zip.append(content, { | ||
|  |               name: filename, | ||
|  |               base64: true | ||
|  |             }); | ||
|  |           } | ||
|  |         } | ||
|  | 
 | ||
|  |         throw new Error('Unsupported media'); | ||
|  |       })); | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "addApp", | ||
|  |     value: function addApp() { | ||
|  |       var _this6 = this; | ||
|  | 
 | ||
|  |       return new Promise(function (resolve) { | ||
|  |         var model = { | ||
|  |           worksheets: _this6._worksheets.filter(Boolean) | ||
|  |         }; | ||
|  |         var xform = new AppXform(); | ||
|  |         var xml = xform.toXml(model); | ||
|  | 
 | ||
|  |         _this6.zip.append(xml, { | ||
|  |           name: 'docProps/app.xml' | ||
|  |         }); | ||
|  | 
 | ||
|  |         resolve(); | ||
|  |       }); | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "addCore", | ||
|  |     value: function addCore() { | ||
|  |       var _this7 = this; | ||
|  | 
 | ||
|  |       return new Promise(function (resolve) { | ||
|  |         var coreXform = new CoreXform(); | ||
|  |         var xml = coreXform.toXml(_this7); | ||
|  | 
 | ||
|  |         _this7.zip.append(xml, { | ||
|  |           name: 'docProps/core.xml' | ||
|  |         }); | ||
|  | 
 | ||
|  |         resolve(); | ||
|  |       }); | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "addSharedStrings", | ||
|  |     value: function addSharedStrings() { | ||
|  |       var _this8 = this; | ||
|  | 
 | ||
|  |       if (this.sharedStrings.count) { | ||
|  |         return new Promise(function (resolve) { | ||
|  |           var sharedStringsXform = new SharedStringsXform(); | ||
|  |           var xml = sharedStringsXform.toXml(_this8.sharedStrings); | ||
|  | 
 | ||
|  |           _this8.zip.append(xml, { | ||
|  |             name: '/xl/sharedStrings.xml' | ||
|  |           }); | ||
|  | 
 | ||
|  |           resolve(); | ||
|  |         }); | ||
|  |       } | ||
|  | 
 | ||
|  |       return Promise.resolve(); | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "addWorkbookRels", | ||
|  |     value: function addWorkbookRels() { | ||
|  |       var _this9 = this; | ||
|  | 
 | ||
|  |       var count = 1; | ||
|  |       var relationships = [{ | ||
|  |         Id: "rId".concat(count++), | ||
|  |         Type: RelType.Styles, | ||
|  |         Target: 'styles.xml' | ||
|  |       }, { | ||
|  |         Id: "rId".concat(count++), | ||
|  |         Type: RelType.Theme, | ||
|  |         Target: 'theme/theme1.xml' | ||
|  |       }]; | ||
|  | 
 | ||
|  |       if (this.sharedStrings.count) { | ||
|  |         relationships.push({ | ||
|  |           Id: "rId".concat(count++), | ||
|  |           Type: RelType.SharedStrings, | ||
|  |           Target: 'sharedStrings.xml' | ||
|  |         }); | ||
|  |       } | ||
|  | 
 | ||
|  |       this._worksheets.forEach(function (worksheet) { | ||
|  |         if (worksheet) { | ||
|  |           worksheet.rId = "rId".concat(count++); | ||
|  |           relationships.push({ | ||
|  |             Id: worksheet.rId, | ||
|  |             Type: RelType.Worksheet, | ||
|  |             Target: "worksheets/sheet".concat(worksheet.id, ".xml") | ||
|  |           }); | ||
|  |         } | ||
|  |       }); | ||
|  | 
 | ||
|  |       return new Promise(function (resolve) { | ||
|  |         var xform = new RelationshipsXform(); | ||
|  |         var xml = xform.toXml(relationships); | ||
|  | 
 | ||
|  |         _this9.zip.append(xml, { | ||
|  |           name: '/xl/_rels/workbook.xml.rels' | ||
|  |         }); | ||
|  | 
 | ||
|  |         resolve(); | ||
|  |       }); | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "addWorkbook", | ||
|  |     value: function addWorkbook() { | ||
|  |       var zip = this.zip; | ||
|  |       var model = { | ||
|  |         worksheets: this._worksheets.filter(Boolean), | ||
|  |         definedNames: this._definedNames.model, | ||
|  |         views: this.views, | ||
|  |         properties: {}, | ||
|  |         calcProperties: {} | ||
|  |       }; | ||
|  |       return new Promise(function (resolve) { | ||
|  |         var xform = new WorkbookXform(); | ||
|  |         xform.prepare(model); | ||
|  |         zip.append(xform.toXml(model), { | ||
|  |           name: '/xl/workbook.xml' | ||
|  |         }); | ||
|  |         resolve(); | ||
|  |       }); | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "_finalize", | ||
|  |     value: function _finalize() { | ||
|  |       var _this10 = this; | ||
|  | 
 | ||
|  |       return new Promise(function (resolve, reject) { | ||
|  |         _this10.stream.on('error', reject); | ||
|  | 
 | ||
|  |         _this10.stream.on('finish', function () { | ||
|  |           resolve(_this10); | ||
|  |         }); | ||
|  | 
 | ||
|  |         _this10.zip.on('error', reject); | ||
|  | 
 | ||
|  |         _this10.zip.finalize(); | ||
|  |       }); | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "definedNames", | ||
|  |     get: function get() { | ||
|  |       return this._definedNames; | ||
|  |     } | ||
|  |   }, { | ||
|  |     key: "nextId", | ||
|  |     get: function get() { | ||
|  |       // find the next unique spot to add worksheet
 | ||
|  |       var i; | ||
|  | 
 | ||
|  |       for (i = 1; i < this._worksheets.length; i++) { | ||
|  |         if (!this._worksheets[i]) { | ||
|  |           return i; | ||
|  |         } | ||
|  |       } | ||
|  | 
 | ||
|  |       return this._worksheets.length || 1; | ||
|  |     } | ||
|  |   }]); | ||
|  | 
 | ||
|  |   return WorkbookWriter; | ||
|  | }(); | ||
|  | 
 | ||
|  | module.exports = WorkbookWriter; | ||
|  | //# sourceMappingURL=workbook-writer.js.map
 |