exceljs
Version:
Excel Workbook Manager - Read and Write xlsx and csv Files.
426 lines (328 loc) • 13.7 kB
JavaScript
;
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
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; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
var fs = require('fs');
var _require = require('events'),
EventEmitter = _require.EventEmitter;
var Stream = require('stream');
var unzip = require('unzipper');
var tmp = require('tmp');
var SAXStream = require('../../utils/sax-stream');
var FlowControl = require('../../utils/flow-control');
var StyleManager = require('../../xlsx/xform/style/styles-xform');
var WorkbookPropertiesManager = require('../../xlsx/xform/book/workbook-properties-xform');
var WorksheetReader = require('./worksheet-reader');
var HyperlinkReader = require('./hyperlink-reader');
tmp.setGracefulCleanup();
var WorkbookReader =
/*#__PURE__*/
function (_EventEmitter) {
_inherits(WorkbookReader, _EventEmitter);
function WorkbookReader(options) {
var _this;
_classCallCheck(this, WorkbookReader);
_this = _possibleConstructorReturn(this, _getPrototypeOf(WorkbookReader).call(this));
_this.options = options = options || {};
_this.styles = new StyleManager();
_this.styles.init();
_this.properties = new WorkbookPropertiesManager(); // worksheet readers, indexed by sheetNo
_this.worksheetReaders = {}; // hyperlink readers, indexed by sheetNo
_this.hyperlinkReaders = {}; // count the open readers
_this.readers = 0; // end of stream check
_this.atEnd = false; // worksheets, deferred for parsing after shared strings reading
_this.waitingWorkSheets = []; // callbacks for temp files cleanup
_this.tempFileCleanupCallbacks = [];
return _this;
}
_createClass(WorkbookReader, [{
key: "_getStream",
value: function _getStream(input) {
if (input instanceof Stream.Readable) {
return input;
}
if (typeof input === 'string') {
return fs.createReadStream(input);
}
throw new Error('Could not recognise input');
}
}, {
key: "read",
value: function read(input, options) {
var _this2 = this;
var stream = this.stream = this._getStream(input);
var zip = this.zip = unzip.Parse();
var pendingWorksheetsTmpFiles = [];
zip.on('entry', function (entry) {
var match;
var sheetNo;
switch (entry.path) {
case '_rels/.rels':
case 'xl/_rels/workbook.xml.rels':
entry.autodrain();
break;
case 'xl/workbook.xml':
_this2._parseWorkbook(entry, options);
break;
case 'xl/sharedStrings.xml':
_this2._parseSharedStrings(entry, options);
break;
case 'xl/styles.xml':
_this2._parseStyles(entry, options);
break;
default:
if (entry.path.match(/xl\/worksheets\/sheet\d+[.]xml/)) {
match = entry.path.match(/xl\/worksheets\/sheet(\d+)[.]xml/);
sheetNo = match[1];
if (_this2.sharedStrings) {
_this2._parseWorksheet(entry, sheetNo, options);
} else {
// create temp file for each worksheet
pendingWorksheetsTmpFiles.push(new Promise(function (resolve, reject) {
tmp.file(function (err, path, fd, cleanupCallback) {
if (err) {
return reject(err);
}
var tempStream = fs.createWriteStream(path);
_this2.waitingWorkSheets.push({
sheetNo: sheetNo,
options: options,
path: path
});
entry.pipe(tempStream);
_this2.tempFileCleanupCallbacks.push(cleanupCallback);
return tempStream.on('finish', function () {
return resolve();
});
});
}));
}
} else if (entry.path.match(/xl\/worksheets\/_rels\/sheet\d+[.]xml.rels/)) {
match = entry.path.match(/xl\/worksheets\/_rels\/sheet(\d+)[.]xml.rels/);
sheetNo = match[1];
_this2._parseHyperlinks(entry, sheetNo, options);
} else {
entry.autodrain();
}
break;
}
});
zip.on('close',
/*#__PURE__*/
_asyncToGenerator(
/*#__PURE__*/
regeneratorRuntime.mark(function _callee() {
var currentBook, processBooks;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.prev = 0;
_context.next = 3;
return Promise.all(pendingWorksheetsTmpFiles);
case 3:
_context.next = 9;
break;
case 5:
_context.prev = 5;
_context.t0 = _context["catch"](0);
_this2.emit('error', _context.t0);
return _context.abrupt("return");
case 9:
if (_this2.waitingWorkSheets.length) {
currentBook = 0;
processBooks = function processBooks() {
var worksheetInfo = _this2.waitingWorkSheets[currentBook];
var entry = fs.createReadStream(worksheetInfo.path);
var sheetNo = worksheetInfo.sheetNo;
var worksheet = _this2._parseWorksheet(entry, sheetNo, worksheetInfo.options);
worksheet.on('finished', function () {
++currentBook;
if (currentBook === _this2.waitingWorkSheets.length) {
// temp files cleaning up
_this2.tempFileCleanupCallbacks.forEach(function (cb) {
cb();
});
_this2.tempFileCleanupCallbacks = [];
_this2.emit('end');
_this2.atEnd = true;
if (!_this2.readers) {
_this2.emit('finished');
}
} else {
setImmediate(processBooks);
}
});
};
setImmediate(processBooks);
} else {
_this2.emit('end');
_this2.atEnd = true;
if (!_this2.readers) {
_this2.emit('finished');
}
}
case 10:
case "end":
return _context.stop();
}
}
}, _callee, null, [[0, 5]]);
})));
zip.on('error', function (err) {
_this2.emit('error', err);
}); // Pipe stream into top flow-control
// this.flowControl.pipe(zip);
stream.pipe(zip);
}
}, {
key: "_emitEntry",
value: function _emitEntry(options, payload) {
if (options.entries === 'emit') {
this.emit('entry', payload);
}
}
}, {
key: "_parseWorkbook",
value: function _parseWorkbook(entry, options) {
this._emitEntry(options, {
type: 'workbook'
});
this.properties.parseStream(entry);
}
}, {
key: "_parseSharedStrings",
value: function _parseSharedStrings(entry, options) {
var _this3 = this;
this._emitEntry(options, {
type: 'shared-strings'
});
var sharedStrings = null;
switch (options.sharedStrings) {
case 'cache':
sharedStrings = this.sharedStrings = [];
break;
case 'emit':
break;
default:
entry.autodrain();
return;
}
var saxStream = new SAXStream();
var inT = false;
var t = null;
var index = 0;
saxStream.sax.on('opentag', function (node) {
if (node.name === 't') {
t = null;
inT = true;
}
});
saxStream.sax.on('closetag', function (node) {
if (inT && node.name === 't') {
if (sharedStrings) {
sharedStrings.push(t);
} else {
_this3.emit('shared-string', {
index: index++,
text: t
});
}
t = null;
}
});
saxStream.sax.on('text', function (text) {
t = t ? t + text : text;
});
saxStream.sax.on('error', function (error) {
_this3.emit('error', error);
});
entry.pipe(saxStream);
}
}, {
key: "_parseStyles",
value: function _parseStyles(entry, options) {
this._emitEntry(options, {
type: 'styles'
});
if (options.styles !== 'cache') {
entry.autodrain();
return;
}
this.styles = new StyleManager();
this.styles.parseStream(entry);
}
}, {
key: "_getReader",
value: function _getReader(Type, collection, sheetNo) {
var _this4 = this;
var reader = collection[sheetNo];
if (!reader) {
reader = new Type(this, sheetNo);
this.readers++;
reader.on('finished', function () {
if (! --_this4.readers) {
if (_this4.atEnd) {
_this4.emit('finished');
}
}
});
collection[sheetNo] = reader;
}
return reader;
}
}, {
key: "_parseWorksheet",
value: function _parseWorksheet(entry, sheetNo, options) {
this._emitEntry(options, {
type: 'worksheet',
id: sheetNo
});
var worksheetReader = this._getReader(WorksheetReader, this.worksheetReaders, sheetNo);
if (options.worksheets === 'emit') {
this.emit('worksheet', worksheetReader);
}
worksheetReader.read(entry, options, this.hyperlinkReaders[sheetNo]);
return worksheetReader;
}
}, {
key: "_parseHyperlinks",
value: function _parseHyperlinks(entry, sheetNo, options) {
this._emitEntry(options, {
type: 'hyerlinks',
id: sheetNo
});
var hyperlinksReader = this._getReader(HyperlinkReader, this.hyperlinkReaders, sheetNo);
if (options.hyperlinks === 'emit') {
this.emit('hyperlinks', hyperlinksReader);
}
hyperlinksReader.read(entry, options);
}
}, {
key: "flowControl",
get: function get() {
if (!this._flowControl) {
this._flowControl = new FlowControl(this.options);
}
return this._flowControl;
}
}]);
return WorkbookReader;
}(EventEmitter); // for reference - these are the valid values for options
WorkbookReader.Options = {
entries: ['emit'],
sharedStrings: ['cache', 'emit'],
styles: ['cache'],
hyperlinks: ['cache', 'emit'],
worksheets: ['emit']
};
module.exports = WorkbookReader;
//# sourceMappingURL=workbook-reader.js.map