UNPKG

libreoffice-file-converter

Version:

Simple NodeJS wrapper for libreoffice CLI for converting office documents to different formats

282 lines (272 loc) 10.3 kB
'use strict'; var fs = require('fs'); var promises = require('fs/promises'); var tmpPromise = require('tmp-promise'); var buffer = require('buffer'); var child_process = require('child_process'); var process = require('process'); var util = require('util'); var url = require('url'); var path = require('path'); var stream = require('stream'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var process__default = /*#__PURE__*/_interopDefault(process); var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __publicField = (obj, key, value) => __defNormalProp(obj, key + "" , value); // src/constants/env.ts var PROGRAM_FILES = "PROGRAMFILES"; var PROGRAM_FILES_86 = "PROGRAMFILES(X86)"; var DARWIN_PATHS = /* @__PURE__ */ __name(() => [ "/Applications/LibreOffice.app/Contents/MacOS/soffice" ], "DARWIN_PATHS"); var LINUX_PATHS = /* @__PURE__ */ __name(() => [ "/usr/bin/libreoffice", "/usr/bin/soffice", "/snap/bin/libreoffice", "/opt/libreoffice/program/soffice", "/opt/libreoffice7.6/program/soffice" ], "LINUX_PATHS"); var WIN32_PATHS = /* @__PURE__ */ __name(() => [ path.join(process__default.default.env[PROGRAM_FILES_86] || "", "LIBREO~1/program/soffice.exe"), path.join(process__default.default.env[PROGRAM_FILES_86] || "", "LibreOffice/program/soffice.exe"), path.join(process__default.default.env[PROGRAM_FILES] || "", "LibreOffice/program/soffice.exe") ], "WIN32_PATHS"); // src/helpers/libreoffice.ts var getLibreOfficeExecutablePaths = /* @__PURE__ */ __name(() => { if (process__default.default.platform === "darwin") { return DARWIN_PATHS(); } if (process__default.default.platform === "linux") { return LINUX_PATHS(); } if (process__default.default.platform === "win32") { return WIN32_PATHS(); } return []; }, "getLibreOfficeExecutablePaths"); var getLibreOfficeExecutablePath = /* @__PURE__ */ __name(async (binaryPaths = []) => { const paths = [ ...binaryPaths, ...getLibreOfficeExecutablePaths() ]; const existingPaths = await Promise.all(paths.map(async (path2) => { try { await promises.access(path2); } catch { return false; } return path2; })); const [path] = existingPaths.filter(Boolean); if (!path) { throw new Error("Could not find soffice binary"); } return path; }, "getLibreOfficeExecutablePath"); var getLibreOfficeCommandArgs = /* @__PURE__ */ __name((installationDir, inputPath, outputDir, format, inputFilter, outputFilter) => { const filterSegment = outputFilter && outputFilter.length > 0 ? `:${outputFilter}` : ""; const args = [ `-env:UserInstallation=${url.pathToFileURL(installationDir).toString()}`, "--headless" ]; if (inputFilter && inputFilter.length > 0) { args.push(`--infilter=${inputFilter}`); } args.push("--convert-to", `${format}${filterSegment}`, "--outdir", outputDir, inputPath); return args; }, "getLibreOfficeCommandArgs"); var hasLibreOfficeError = /* @__PURE__ */ __name((stderr) => { return stderr?.toLowerCase()?.includes("error:"); }, "hasLibreOfficeError"); // src/helpers/child-process.ts var isBuffer = /* @__PURE__ */ __name((value) => { return buffer.Buffer.isBuffer(value); }, "isBuffer"); var processOutputToString = /* @__PURE__ */ __name((processOutput) => { return isBuffer(processOutput) ? processOutput.toString("utf-8") : processOutput; }, "processOutputToString"); var execFileAsync = /* @__PURE__ */ __name((path, args, options, debug) => { return new Promise((resolve, reject) => { child_process.execFile(path, args, options, (error, stdout, stderr) => { const stderrString = processOutputToString(stderr); const stdoutString = processOutputToString(stdout); if (debug) { const debugInfo = util.inspect({ args, path, stderr: stderrString, stdout: stdoutString }, { colors: true, sorted: true }); process__default.default.stdout.write(`LibreOffice debug output: ${debugInfo} `); } const libreOfficeError = hasLibreOfficeError(stderrString); if (error || libreOfficeError) { return reject(error || new Error(stderrString)); } return resolve(); }); }); }, "execFileAsync"); var getTemporaryFilePath = /* @__PURE__ */ __name((temporaryDir) => { return path.join(temporaryDir, "source"); }, "getTemporaryFilePath"); var getProcessedFilePath = /* @__PURE__ */ __name((temporaryDirPath, inputPath, format) => { const insideTemporaryDir = inputPath.startsWith(temporaryDirPath); if (insideTemporaryDir) { return `${inputPath}.${format}`; } const inputPathSegments = inputPath.split(path.sep); const inputFileNameSegment = inputPathSegments.length > 0 ? inputPathSegments[inputPathSegments.length - 1] : inputPathSegments[0]; const inputFileNameSegments = inputFileNameSegment?.split("."); const inputFileName = inputFileNameSegments?.length && inputFileNameSegments.length > 1 ? inputFileNameSegments?.slice(0, -1).join(".") : inputFileNameSegments?.[0]; return `${temporaryDirPath}${path.sep}${inputFileName}.${format}`; }, "getProcessedFilePath"); var writeStream = /* @__PURE__ */ __name((path, readStream) => { return new Promise((resolve, reject) => { const writeStream2 = fs.createWriteStream(path); stream.pipeline(readStream, writeStream2, (error) => { if (error) { return reject(error); } return resolve(); }); }); }, "writeStream"); // src/helpers/primitives.ts var isObject = /* @__PURE__ */ __name((item) => { return Boolean(item && typeof item === "object" && !Array.isArray(item)); }, "isObject"); var deepMerge = /* @__PURE__ */ __name((...objects) => { return objects.reduce((target, source) => { Object.keys(source).forEach((key) => { const targetValue = target[key]; const sourceValue = source[key]; if (Array.isArray(targetValue) && Array.isArray(sourceValue)) { target[key] = [ ...targetValue, ...sourceValue ]; return; } if (isObject(targetValue) && isObject(sourceValue)) { target[key] = deepMerge(targetValue, sourceValue); return; } target[key] = sourceValue; }); return target; }, {}); }, "deepMerge"); // src/libreoffice-file-converter.ts var _LibreOfficeFileConverter = class _LibreOfficeFileConverter { /** * Create an instance of the LibreOfficeFileConverter. * * @example * ```ts * const libreOfficeFileConverter = new LibreOfficeFileConverter({ childProcessOptions: { timeout: 60 * 1000 } }); * ``` * * @param options The LibreOfficeFileConverter options. * * @constructor * @public */ constructor(options = {}) { __publicField(this, "_options"); this._options = options; tmpPromise.setGracefulCleanup(); } /** * Converts provided input to the requested format. * * @example * ```ts * const outputBuffer = await libreOfficeFileConverter.convert({ * buffer: inputBuffer, * format: 'pdf', * input: 'buffer', * output: 'buffer', * }); * ``` * * @param options Convert options: input and output type, format, filter, converter options. * * @returns Buffer, readable stream or void depending on the convert options. * * @public */ async convert(options) { const { filter, format, inputFilter, options: callOptions = {}, outputFilter } = options; const mergedOptions = this.mergeOptions(callOptions); const { tmpOptions } = mergedOptions; const temporaryDir = await tmpPromise.dir({ prefix: "libreoffice-file-converter", unsafeCleanup: true, ...tmpOptions }); const inputPath = await this.write(options, temporaryDir.path); await this.process(inputPath, temporaryDir.path, format, inputFilter || filter, outputFilter, mergedOptions); return this.read(options, temporaryDir.path, inputPath); } mergeOptions(options = {}) { return deepMerge(this._options, options); } async process(inputPath, outputDir, format, inputFilter, outputFilter, options = {}) { const { binaryPaths, childProcessOptions, debug, tmpOptions } = options; const libreOfficeExecutablePath = await getLibreOfficeExecutablePath(binaryPaths); const installationDir = await tmpPromise.dir({ prefix: "soffice", unsafeCleanup: true, ...tmpOptions }); const libreOfficeCommandArgs = getLibreOfficeCommandArgs(installationDir.path, inputPath, outputDir, format, inputFilter, outputFilter); await execFileAsync(libreOfficeExecutablePath, libreOfficeCommandArgs, childProcessOptions, debug); } async read(options, temporaryDirPath, inputPath) { const { format, output } = options; const processedFilePath = getProcessedFilePath(temporaryDirPath, inputPath, format); if (output === "buffer") { return promises.readFile(processedFilePath); } if (output === "file") { const { outputPath } = options; const stream = fs.createReadStream(processedFilePath); return writeStream(outputPath, stream); } if (output === "stream") { return fs.createReadStream(processedFilePath); } } async write(options, temporaryDirPath) { const { input } = options; const temporaryFilePath = getTemporaryFilePath(temporaryDirPath); if (input === "buffer") { const { buffer } = options; await promises.writeFile(temporaryFilePath, buffer); return temporaryFilePath; } if (input === "file") { const { inputPath } = options; return inputPath; } if (input === "stream") { const { stream } = options; await writeStream(temporaryFilePath, stream); return temporaryFilePath; } return temporaryFilePath; } }; __name(_LibreOfficeFileConverter, "LibreOfficeFileConverter"); var LibreOfficeFileConverter = _LibreOfficeFileConverter; exports.LibreOfficeFileConverter = LibreOfficeFileConverter; //# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map