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.
		
		
		
		
		
			
		
			
				
					348 lines
				
				9.9 KiB
			
		
		
			
		
	
	
					348 lines
				
				9.9 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								const fs = require('fs');
							 | 
						||
| 
								 | 
							
								const Archiver = require('archiver');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const StreamBuf = require('../../utils/stream-buf');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const RelType = require('../../xlsx/rel-type');
							 | 
						||
| 
								 | 
							
								const StylesXform = require('../../xlsx/xform/style/styles-xform');
							 | 
						||
| 
								 | 
							
								const SharedStrings = require('../../utils/shared-strings');
							 | 
						||
| 
								 | 
							
								const DefinedNames = require('../../doc/defined-names');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const CoreXform = require('../../xlsx/xform/core/core-xform');
							 | 
						||
| 
								 | 
							
								const RelationshipsXform = require('../../xlsx/xform/core/relationships-xform');
							 | 
						||
| 
								 | 
							
								const ContentTypesXform = require('../../xlsx/xform/core/content-types-xform');
							 | 
						||
| 
								 | 
							
								const AppXform = require('../../xlsx/xform/core/app-xform');
							 | 
						||
| 
								 | 
							
								const WorkbookXform = require('../../xlsx/xform/book/workbook-xform');
							 | 
						||
| 
								 | 
							
								const SharedStringsXform = require('../../xlsx/xform/strings/shared-strings-xform');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const WorksheetWriter = require('./worksheet-writer');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const theme1Xml = require('../../xlsx/xml/theme1.js');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class WorkbookWriter {
							 | 
						||
| 
								 | 
							
								  constructor(options) {
							 | 
						||
| 
								 | 
							
								    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()]);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  get definedNames() {
							 | 
						||
| 
								 | 
							
								    return this._definedNames;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _openStream(path) {
							 | 
						||
| 
								 | 
							
								    const stream = new StreamBuf({bufSize: 65536, batch: true});
							 | 
						||
| 
								 | 
							
								    this.zip.append(stream, {name: path});
							 | 
						||
| 
								 | 
							
								    stream.on('finish', () => {
							 | 
						||
| 
								 | 
							
								      stream.emit('zipped');
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    return stream;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _commitWorksheets() {
							 | 
						||
| 
								 | 
							
								    const commitWorksheet = function(worksheet) {
							 | 
						||
| 
								 | 
							
								      if (!worksheet.committed) {
							 | 
						||
| 
								 | 
							
								        return new Promise(resolve => {
							 | 
						||
| 
								 | 
							
								          worksheet.stream.on('zipped', () => {
							 | 
						||
| 
								 | 
							
								            resolve();
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								          worksheet.commit();
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      return Promise.resolve();
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    // if there are any uncommitted worksheets, commit them now and wait
							 | 
						||
| 
								 | 
							
								    const promises = this._worksheets.map(commitWorksheet);
							 | 
						||
| 
								 | 
							
								    if (promises.length) {
							 | 
						||
| 
								 | 
							
								      return Promise.all(promises);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return Promise.resolve();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  async commit() {
							 | 
						||
| 
								 | 
							
								    // commit all worksheets, then add suplimentary files
							 | 
						||
| 
								 | 
							
								    await this.promise;
							 | 
						||
| 
								 | 
							
								    await this.addMedia();
							 | 
						||
| 
								 | 
							
								    await this._commitWorksheets();
							 | 
						||
| 
								 | 
							
								    await Promise.all([
							 | 
						||
| 
								 | 
							
								      this.addContentTypes(),
							 | 
						||
| 
								 | 
							
								      this.addApp(),
							 | 
						||
| 
								 | 
							
								      this.addCore(),
							 | 
						||
| 
								 | 
							
								      this.addSharedStrings(),
							 | 
						||
| 
								 | 
							
								      this.addStyles(),
							 | 
						||
| 
								 | 
							
								      this.addWorkbookRels(),
							 | 
						||
| 
								 | 
							
								    ]);
							 | 
						||
| 
								 | 
							
								    await this.addWorkbook();
							 | 
						||
| 
								 | 
							
								    return this._finalize();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  get nextId() {
							 | 
						||
| 
								 | 
							
								    // find the next unique spot to add worksheet
							 | 
						||
| 
								 | 
							
								    let i;
							 | 
						||
| 
								 | 
							
								    for (i = 1; i < this._worksheets.length; i++) {
							 | 
						||
| 
								 | 
							
								      if (!this._worksheets[i]) {
							 | 
						||
| 
								 | 
							
								        return i;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return this._worksheets.length || 1;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  addImage(image) {
							 | 
						||
| 
								 | 
							
								    const id = this.media.length;
							 | 
						||
| 
								 | 
							
								    const medium = Object.assign({}, image, {type: 'image', name: `image${id}.${image.extension}`});
							 | 
						||
| 
								 | 
							
								    this.media.push(medium);
							 | 
						||
| 
								 | 
							
								    return id;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  getImage(id) {
							 | 
						||
| 
								 | 
							
								    return this.media[id];
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  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 || {};
							 | 
						||
| 
								 | 
							
								    const 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
							 | 
						||
| 
								 | 
							
								      );
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const id = this.nextId;
							 | 
						||
| 
								 | 
							
								    name = name || `sheet${id}`;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const worksheet = new WorksheetWriter({
							 | 
						||
| 
								 | 
							
								      id,
							 | 
						||
| 
								 | 
							
								      name,
							 | 
						||
| 
								 | 
							
								      workbook: this,
							 | 
						||
| 
								 | 
							
								      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;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  getWorksheet(id) {
							 | 
						||
| 
								 | 
							
								    if (id === undefined) {
							 | 
						||
| 
								 | 
							
								      return this._worksheets.find(() => true);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (typeof id === 'number') {
							 | 
						||
| 
								 | 
							
								      return this._worksheets[id];
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (typeof id === 'string') {
							 | 
						||
| 
								 | 
							
								      return this._worksheets.find(worksheet => worksheet && worksheet.name === id);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return undefined;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  addStyles() {
							 | 
						||
| 
								 | 
							
								    return new Promise(resolve => {
							 | 
						||
| 
								 | 
							
								      this.zip.append(this.styles.xml, {name: 'xl/styles.xml'});
							 | 
						||
| 
								 | 
							
								      resolve();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  addThemes() {
							 | 
						||
| 
								 | 
							
								    return new Promise(resolve => {
							 | 
						||
| 
								 | 
							
								      this.zip.append(theme1Xml, {name: 'xl/theme/theme1.xml'});
							 | 
						||
| 
								 | 
							
								      resolve();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  addOfficeRels() {
							 | 
						||
| 
								 | 
							
								    return new Promise(resolve => {
							 | 
						||
| 
								 | 
							
								      const xform = new RelationshipsXform();
							 | 
						||
| 
								 | 
							
								      const 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'},
							 | 
						||
| 
								 | 
							
								      ]);
							 | 
						||
| 
								 | 
							
								      this.zip.append(xml, {name: '/_rels/.rels'});
							 | 
						||
| 
								 | 
							
								      resolve();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  addContentTypes() {
							 | 
						||
| 
								 | 
							
								    return new Promise(resolve => {
							 | 
						||
| 
								 | 
							
								      const model = {
							 | 
						||
| 
								 | 
							
								        worksheets: this._worksheets.filter(Boolean),
							 | 
						||
| 
								 | 
							
								        sharedStrings: this.sharedStrings,
							 | 
						||
| 
								 | 
							
								        commentRefs: this.commentRefs,
							 | 
						||
| 
								 | 
							
								        media: this.media,
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								      const xform = new ContentTypesXform();
							 | 
						||
| 
								 | 
							
								      const xml = xform.toXml(model);
							 | 
						||
| 
								 | 
							
								      this.zip.append(xml, {name: '[Content_Types].xml'});
							 | 
						||
| 
								 | 
							
								      resolve();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  addMedia() {
							 | 
						||
| 
								 | 
							
								    return Promise.all(
							 | 
						||
| 
								 | 
							
								      this.media.map(medium => {
							 | 
						||
| 
								 | 
							
								        if (medium.type === 'image') {
							 | 
						||
| 
								 | 
							
								          const filename = `xl/media/${medium.name}`;
							 | 
						||
| 
								 | 
							
								          if (medium.filename) {
							 | 
						||
| 
								 | 
							
								            return this.zip.file(medium.filename, {name: filename});
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								          if (medium.buffer) {
							 | 
						||
| 
								 | 
							
								            return this.zip.append(medium.buffer, {name: filename});
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								          if (medium.base64) {
							 | 
						||
| 
								 | 
							
								            const dataimg64 = medium.base64;
							 | 
						||
| 
								 | 
							
								            const content = dataimg64.substring(dataimg64.indexOf(',') + 1);
							 | 
						||
| 
								 | 
							
								            return this.zip.append(content, {name: filename, base64: true});
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        throw new Error('Unsupported media');
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  addApp() {
							 | 
						||
| 
								 | 
							
								    return new Promise(resolve => {
							 | 
						||
| 
								 | 
							
								      const model = {
							 | 
						||
| 
								 | 
							
								        worksheets: this._worksheets.filter(Boolean),
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								      const xform = new AppXform();
							 | 
						||
| 
								 | 
							
								      const xml = xform.toXml(model);
							 | 
						||
| 
								 | 
							
								      this.zip.append(xml, {name: 'docProps/app.xml'});
							 | 
						||
| 
								 | 
							
								      resolve();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  addCore() {
							 | 
						||
| 
								 | 
							
								    return new Promise(resolve => {
							 | 
						||
| 
								 | 
							
								      const coreXform = new CoreXform();
							 | 
						||
| 
								 | 
							
								      const xml = coreXform.toXml(this);
							 | 
						||
| 
								 | 
							
								      this.zip.append(xml, {name: 'docProps/core.xml'});
							 | 
						||
| 
								 | 
							
								      resolve();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  addSharedStrings() {
							 | 
						||
| 
								 | 
							
								    if (this.sharedStrings.count) {
							 | 
						||
| 
								 | 
							
								      return new Promise(resolve => {
							 | 
						||
| 
								 | 
							
								        const sharedStringsXform = new SharedStringsXform();
							 | 
						||
| 
								 | 
							
								        const xml = sharedStringsXform.toXml(this.sharedStrings);
							 | 
						||
| 
								 | 
							
								        this.zip.append(xml, {name: '/xl/sharedStrings.xml'});
							 | 
						||
| 
								 | 
							
								        resolve();
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return Promise.resolve();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  addWorkbookRels() {
							 | 
						||
| 
								 | 
							
								    let count = 1;
							 | 
						||
| 
								 | 
							
								    const relationships = [
							 | 
						||
| 
								 | 
							
								      {Id: `rId${count++}`, Type: RelType.Styles, Target: 'styles.xml'},
							 | 
						||
| 
								 | 
							
								      {Id: `rId${count++}`, Type: RelType.Theme, Target: 'theme/theme1.xml'},
							 | 
						||
| 
								 | 
							
								    ];
							 | 
						||
| 
								 | 
							
								    if (this.sharedStrings.count) {
							 | 
						||
| 
								 | 
							
								      relationships.push({
							 | 
						||
| 
								 | 
							
								        Id: `rId${count++}`,
							 | 
						||
| 
								 | 
							
								        Type: RelType.SharedStrings,
							 | 
						||
| 
								 | 
							
								        Target: 'sharedStrings.xml',
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    this._worksheets.forEach(worksheet => {
							 | 
						||
| 
								 | 
							
								      if (worksheet) {
							 | 
						||
| 
								 | 
							
								        worksheet.rId = `rId${count++}`;
							 | 
						||
| 
								 | 
							
								        relationships.push({
							 | 
						||
| 
								 | 
							
								          Id: worksheet.rId,
							 | 
						||
| 
								 | 
							
								          Type: RelType.Worksheet,
							 | 
						||
| 
								 | 
							
								          Target: `worksheets/sheet${worksheet.id}.xml`,
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    return new Promise(resolve => {
							 | 
						||
| 
								 | 
							
								      const xform = new RelationshipsXform();
							 | 
						||
| 
								 | 
							
								      const xml = xform.toXml(relationships);
							 | 
						||
| 
								 | 
							
								      this.zip.append(xml, {name: '/xl/_rels/workbook.xml.rels'});
							 | 
						||
| 
								 | 
							
								      resolve();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  addWorkbook() {
							 | 
						||
| 
								 | 
							
								    const {zip} = this;
							 | 
						||
| 
								 | 
							
								    const model = {
							 | 
						||
| 
								 | 
							
								      worksheets: this._worksheets.filter(Boolean),
							 | 
						||
| 
								 | 
							
								      definedNames: this._definedNames.model,
							 | 
						||
| 
								 | 
							
								      views: this.views,
							 | 
						||
| 
								 | 
							
								      properties: {},
							 | 
						||
| 
								 | 
							
								      calcProperties: {},
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return new Promise(resolve => {
							 | 
						||
| 
								 | 
							
								      const xform = new WorkbookXform();
							 | 
						||
| 
								 | 
							
								      xform.prepare(model);
							 | 
						||
| 
								 | 
							
								      zip.append(xform.toXml(model), {name: '/xl/workbook.xml'});
							 | 
						||
| 
								 | 
							
								      resolve();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _finalize() {
							 | 
						||
| 
								 | 
							
								    return new Promise((resolve, reject) => {
							 | 
						||
| 
								 | 
							
								      this.stream.on('error', reject);
							 | 
						||
| 
								 | 
							
								      this.stream.on('finish', () => {
							 | 
						||
| 
								 | 
							
								        resolve(this);
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								      this.zip.on('error', reject);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      this.zip.finalize();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = WorkbookWriter;
							 |