pdflatex-ts
Version:
A TypeScript library for converting LaTeX files to PDF using pdflatex. Supports both file conversion and dynamic content generation.
161 lines • 5.82 kB
JavaScript
import * as fs from 'fs';
import * as path from 'path';
import { spawn } from 'child_process';
import { FileUtils } from './utils/file-utils';
import process from 'process';
export class LatexToPdfConverter {
convert(input, options = {}, callback) {
const startTime = Date.now();
try {
FileUtils.validateInputFile(input);
const config = this.setupConfiguration(input, options);
FileUtils.ensureDirectoryExists(config.outputDir);
this.executeConversion(input, config, startTime, callback);
}
catch (error) {
const executionTime = Date.now() - startTime;
callback(error, {
success: false,
error: error.message,
executionTime,
});
}
}
convertAsync(input, options = {}) {
return new Promise((resolve, reject) => {
this.convert(input, options, (error, result) => {
if (error) {
reject(error);
}
else {
resolve(result);
}
});
});
}
async convertFromContent(latexContent, filename, options = {}) {
const tempDir = path.join(process.cwd(), 'temp');
const tempFile = path.join(tempDir, `${filename}.tex`);
try {
FileUtils.ensureDirectoryExists(tempDir);
fs.writeFileSync(tempFile, latexContent, 'utf8');
const result = await this.convertAsync(tempFile, options);
FileUtils.safeDelete(tempFile);
return result;
}
catch (error) {
FileUtils.safeDelete(tempFile);
throw error;
}
}
setupConfiguration(input, options) {
const inputParsed = path.parse(input);
const outputDir = options.output
? path.parse(options.output).dir
: LatexToPdfConverter.DEFAULT_OUTPUT_DIR;
const outputFile = options.output
? path.parse(options.output).name
: inputParsed.name;
return {
outputDir,
outputFile,
timeout: options.timeout ?? LatexToPdfConverter.DEFAULT_TIMEOUT,
debug: options.debug ?? false,
cleanupAuxFiles: options.cleanupAuxFiles ?? true,
};
}
executeConversion(input, config, startTime, callback) {
let processKilled = false;
let outputBuffer = '';
let errorBuffer = '';
const pdflatexProcess = spawn('pdflatex', [
'--jobname',
config.outputFile,
'-output-directory',
config.outputDir,
input,
]);
pdflatexProcess.stdout?.on('data', (data) => {
const output = data.toString();
outputBuffer += output;
if (config.debug) {
console.log('STDOUT:', output);
}
});
pdflatexProcess.stderr?.on('data', (data) => {
const error = data.toString();
errorBuffer += error;
if (config.debug) {
console.error('STDERR:', error);
}
});
pdflatexProcess.on('exit', (code) => {
const executionTime = Date.now() - startTime;
if (config.cleanupAuxFiles) {
this.cleanupAuxiliaryFiles(config.outputDir, config.outputFile);
}
if (processKilled) {
callback(new Error('Conversion timeout'), {
success: false,
error: 'Process timed out',
executionTime,
});
return;
}
if (code === 0) {
const outputPath = path.join(config.outputDir, `${config.outputFile}.pdf`);
if (fs.existsSync(outputPath)) {
callback(null, {
success: true,
outputPath,
executionTime,
});
}
else {
callback(new Error('PDF file was not created'), {
success: false,
error: 'PDF file was not created',
executionTime,
});
}
}
else {
callback(new Error(`pdflatex failed with code ${code}`), {
success: false,
error: `pdflatex failed with code ${code}. Error: ${errorBuffer}`,
executionTime,
});
}
});
pdflatexProcess.on('error', (error) => {
const executionTime = Date.now() - startTime;
callback(error, {
success: false,
error: `Process error: ${error.message}`,
executionTime,
});
});
const timeoutId = setTimeout(() => {
processKilled = true;
pdflatexProcess.kill('SIGTERM');
setTimeout(() => {
if (!pdflatexProcess.killed) {
pdflatexProcess.kill('SIGKILL');
}
}, 5000);
}, config.timeout);
pdflatexProcess.on('exit', () => {
clearTimeout(timeoutId);
});
}
cleanupAuxiliaryFiles(outputDir, outputFile) {
const auxiliaryExtensions = ['.aux', '.log', '.out', '.toc', '.nav', '.snm'];
auxiliaryExtensions.forEach((ext) => {
const filePath = path.join(outputDir, `${outputFile}${ext}`);
FileUtils.safeDelete(filePath);
});
}
}
LatexToPdfConverter.DEFAULT_TIMEOUT = 60000;
LatexToPdfConverter.DEFAULT_OUTPUT_DIR = 'output';
//# sourceMappingURL=latex-converter.js.map