UNPKG

write-excel-file

Version:

Write simple `*.xlsx` files in a browser or Node.js

333 lines (329 loc) 14.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = writeXlsxFile; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _fs = _interopRequireDefault(require("fs")); var _path = _interopRequireDefault(require("path")); var _os = _interopRequireDefault(require("os")); var _stream = _interopRequireWildcard(require("stream")); var _archive = _interopRequireDefault(require("./archive.js")); var _getImageFileName = _interopRequireDefault(require("./getImageFileName.js")); var _workbookXml = _interopRequireDefault(require("./files/workbook.xml.js")); var _workbookXmlRels = _interopRequireDefault(require("./files/workbook.xml.rels.js")); var _rels2 = _interopRequireDefault(require("./files/rels.js")); var _Content_TypesXml = _interopRequireDefault(require("./files/[Content_Types].xml.js")); var _drawingXml = _interopRequireDefault(require("./files/drawing.xml.js")); var _drawingXmlRels = _interopRequireDefault(require("./files/drawing.xml.rels.js")); var _sheetXmlRels = _interopRequireDefault(require("./files/sheet.xml.rels.js")); var _sharedStringsXml = _interopRequireDefault(require("./files/sharedStrings.xml.js")); var _stylesXml = _interopRequireDefault(require("./files/styles.xml.js")); var _writeXlsxFileCommon = require("./writeXlsxFile.common.js"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; } function _createForOfIteratorHelperLoose(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (t) return (t = t.call(r)).next.bind(t); if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var o = 0; return function () { return o >= r.length ? { done: !0 } : { done: !1, value: r[o++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function writeXlsxFile(_x) { return _writeXlsxFile.apply(this, arguments); } // According to Node.js docs: // https://nodejs.org/api/fs.html#fswritefilefile-data-options-callback // `contents` argument could be of type: // * string — File path // * Buffer // * TypedArray // * DataView function _writeXlsxFile() { _writeXlsxFile = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee(data) { var _ref, filePath, buffer, sheetName, sheetNames, schema, columns, images, headerStyle, getHeaderStyle, fontFamily, fontSize, orientation, stickyRowsCount, stickyColumnsCount, showGridLines, rightToLeft, dateFormat, archive, _generateSheets, sheets, getSharedStrings, getStyles, root, xl, mediaPath, drawingsPath, drawingsRelsPath, _rels, worksheetsPath, worksheetsRelsPath, promises, _iterator2, _step2, _step2$value, id, _data, _images, _iterator3, _step3, image, imageContentReadableStream, imageFilePath, _args = arguments; return _regenerator["default"].wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: _ref = _args.length > 1 && _args[1] !== undefined ? _args[1] : {}, filePath = _ref.filePath, buffer = _ref.buffer, sheetName = _ref.sheet, sheetNames = _ref.sheets, schema = _ref.schema, columns = _ref.columns, images = _ref.images, headerStyle = _ref.headerStyle, getHeaderStyle = _ref.getHeaderStyle, fontFamily = _ref.fontFamily, fontSize = _ref.fontSize, orientation = _ref.orientation, stickyRowsCount = _ref.stickyRowsCount, stickyColumnsCount = _ref.stickyColumnsCount, showGridLines = _ref.showGridLines, rightToLeft = _ref.rightToLeft, dateFormat = _ref.dateFormat; // I dunno why it uses `Archive` here instead of something like `JSZip` // that is used in `writeXlsxFileBrowser.js`. archive = new _archive["default"](filePath); _generateSheets = (0, _writeXlsxFileCommon.generateSheets)({ data: data, sheetName: sheetName, sheetNames: sheetNames, schema: schema, columns: columns, images: images, headerStyle: headerStyle, getHeaderStyle: getHeaderStyle, fontFamily: fontFamily, fontSize: fontSize, orientation: orientation, stickyRowsCount: stickyRowsCount, stickyColumnsCount: stickyColumnsCount, showGridLines: showGridLines, rightToLeft: rightToLeft, dateFormat: dateFormat }), sheets = _generateSheets.sheets, getSharedStrings = _generateSheets.getSharedStrings, getStyles = _generateSheets.getStyles; // There doesn't seem to be a way to just append a file into a subdirectory // in `archiver` library, hence using a hacky temporary directory workaround. // https://www.npmjs.com/package/archiver _context.next = 5; return createTempDirectory(); case 5: root = _context.sent; _context.next = 8; return createDirectory(_path["default"].join(root, 'xl')); case 8: xl = _context.sent; _context.next = 11; return createDirectory(_path["default"].join(xl, 'media')); case 11: mediaPath = _context.sent; _context.next = 14; return createDirectory(_path["default"].join(xl, 'drawings')); case 14: drawingsPath = _context.sent; _context.next = 17; return createDirectory(_path["default"].join(drawingsPath, '_rels')); case 17: drawingsRelsPath = _context.sent; _context.next = 20; return createDirectory(_path["default"].join(xl, '_rels')); case 20: _rels = _context.sent; _context.next = 23; return createDirectory(_path["default"].join(xl, 'worksheets')); case 23: worksheetsPath = _context.sent; _context.next = 26; return createDirectory(_path["default"].join(worksheetsPath, '_rels')); case 26: worksheetsRelsPath = _context.sent; promises = [writeFile(_path["default"].join(_rels, 'workbook.xml.rels'), (0, _workbookXmlRels["default"])({ sheets: sheets })), writeFile(_path["default"].join(xl, 'workbook.xml'), (0, _workbookXml["default"])({ sheets: sheets, stickyRowsCount: stickyRowsCount, stickyColumnsCount: stickyColumnsCount })), writeFile(_path["default"].join(xl, 'styles.xml'), (0, _stylesXml["default"])(getStyles())), writeFile(_path["default"].join(xl, 'sharedStrings.xml'), (0, _sharedStringsXml["default"])(getSharedStrings()))]; for (_iterator2 = _createForOfIteratorHelperLoose(sheets); !(_step2 = _iterator2()).done;) { _step2$value = _step2.value, id = _step2$value.id, _data = _step2$value.data, _images = _step2$value.images; promises.push(writeFile(_path["default"].join(worksheetsPath, "sheet".concat(id, ".xml")), _data)); promises.push(writeFile(_path["default"].join(worksheetsRelsPath, "sheet".concat(id, ".xml.rels")), (0, _sheetXmlRels["default"])({ id: id, images: _images }))); if (_images) { promises.push(writeFile(_path["default"].join(drawingsPath, "drawing".concat(id, ".xml")), (0, _drawingXml["default"])({ images: _images }))); promises.push(writeFile(_path["default"].join(drawingsRelsPath, "drawing".concat(id, ".xml.rels")), (0, _drawingXmlRels["default"])({ images: _images, sheetId: id }))); // Copy images to `xl/media` folder. for (_iterator3 = _createForOfIteratorHelperLoose(_images); !(_step3 = _iterator3()).done;) { image = _step3.value; imageContentReadableStream = getReadableStream(image.content); imageFilePath = _path["default"].join(mediaPath, (0, _getImageFileName["default"])(image, { sheetId: id, sheetImages: _images })); promises.push(writeFileFromStream(imageFilePath, imageContentReadableStream)); } } } _context.next = 31; return Promise.all(promises); case 31: archive.directory(xl, 'xl'); archive.append(_rels2["default"], '_rels/.rels'); archive.append((0, _Content_TypesXml["default"])({ images: images, sheets: sheets }), '[Content_Types].xml'); if (!filePath) { _context.next = 41; break; } _context.next = 37; return archive.write(); case 37: _context.next = 39; return removeDirectoryWithLegacyNodeVersionsSupport(root); case 39: _context.next = 46; break; case 41: if (!buffer) { _context.next = 45; break; } return _context.abrupt("return", streamToBuffer(archive.write())); case 45: return _context.abrupt("return", archive.write()); case 46: case "end": return _context.stop(); } }, _callee); })); return _writeXlsxFile.apply(this, arguments); } function writeFile(path, contents) { return new Promise(function (resolve, reject) { _fs["default"].writeFile(path, contents, 'utf-8', function (error) { if (error) { return reject(error); } resolve(); }); }); } function createDirectory(path) { return new Promise(function (resolve, reject) { _fs["default"].mkdir(path, function (error) { if (error) { return reject(error); } resolve(path); }); }); } function createTempDirectory() { return new Promise(function (resolve, reject) { _fs["default"].mkdtemp(_path["default"].join(_os["default"].tmpdir(), 'write-excel-file-'), function (error, directoryPath) { if (error) { return reject(error); } resolve(directoryPath); }); }); } function removeDirectoryWithLegacyNodeVersionsSupport(path) { if (_fs["default"].rm) { return removeDirectory(path); } else { removeDirectoryLegacySync(path); return Promise.resolve(); } } // `fs.rm()` is available in Node.js since `14.14.0`. function removeDirectory(path) { return new Promise(function (resolve, reject) { _fs["default"].rm(path, { recursive: true, force: true }, function (error) { if (error) { return reject(error); } resolve(); }); }); } // For Node.js versions below `14.14.0`. function removeDirectoryLegacySync(directoryPath) { var childNames = _fs["default"].readdirSync(directoryPath); for (var _iterator = _createForOfIteratorHelperLoose(childNames), _step; !(_step = _iterator()).done;) { var childName = _step.value; var childPath = _path["default"].join(directoryPath, childName); var stats = _fs["default"].statSync(childPath); if (childPath === '.' || childPath === '..') { // Skip. } else if (stats.isDirectory()) { // Remove subdirectory recursively. removeDirectoryLegacySync(childPath); } else { // Remove file. _fs["default"].unlinkSync(childPath); } } _fs["default"].rmdirSync(directoryPath); } // https://stackoverflow.com/a/67729663 function streamToBuffer(stream) { return new Promise(function (resolve, reject) { var chunks = []; stream.on('data', function (chunk) { return chunks.push(chunk); }); stream.on('end', function () { return resolve(Buffer.concat(chunks)); }); stream.on('error', reject); }); } function copyFile(fromPath, toPath) { return new Promise(function (resolve, reject) { _fs["default"].copyFile(fromPath, toPath, function (error) { if (error) { return reject(error); } resolve(); }); }); } function getReadableStream(source) { if (source instanceof _stream["default"]) { return source; } if (source instanceof Buffer) { return _stream.Readable.from(source); } if (typeof source === 'string') { return _fs["default"].createReadStream(source); } throw new Error('Unsupported content source: couldn\'t convert it to a readable stream'); } function writeFileFromStream(filePath, readableStream) { var writableStream = _fs["default"].createWriteStream(filePath); readableStream.pipe(writableStream); return new Promise(function (resolve) { return writableStream.on('finish', resolve); }); } //# sourceMappingURL=writeXlsxFileNode.js.map