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
						
					
					
				| "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
 |