write-excel-file
Version:
Write simple `*.xlsx` files in a browser or Node.js
333 lines (329 loc) • 14.5 kB
JavaScript
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
;