n8n-nodes-json-to-pdf
Version:
Convert Markdown/JSON into PDF (single document or e-book) for n8n
176 lines • 7.75 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JsonToPdf = void 0;
const pdfkit_1 = __importDefault(require("pdfkit"));
const markdown_it_1 = __importDefault(require("markdown-it"));
const get_stream_1 = __importDefault(require("get-stream"));
const stream_1 = require("stream");
class JsonToPdf {
constructor() {
this.description = {
displayName: 'JSON to PDF',
name: 'jsonToPdf',
icon: 'file:pdf-file-svgrepo-com.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"]}}',
description: 'Convert JSON / Markdown into a PDF (single page or e-book)',
defaults: { name: 'JSON to PDF' },
inputs: ['main'],
outputs: ['main'],
properties: [
/* core */
{
displayName: 'Operation',
name: 'operation',
type: 'options',
options: [
{ name: 'Single PDF', value: 'single' },
{ name: 'Generate E-book', value: 'ebook' },
],
default: 'single',
},
{
displayName: 'Raw Input',
name: 'rawInput',
type: 'json',
default: '',
description: 'Single PDF: string ou { data } — E-book: { title, data[] }',
},
{
displayName: 'Filename',
name: 'fileName',
type: 'string',
default: 'output.pdf',
},
/* appearance */
{
displayName: 'Font',
name: 'font',
type: 'options',
options: [
{ name: 'Helvetica', value: 'Helvetica' },
{ name: 'Times-Roman', value: 'Times-Roman' },
{ name: 'Courier', value: 'Courier' },
{ name: 'Helvetica-Bold', value: 'Helvetica-Bold' },
],
default: 'Helvetica',
},
{ displayName: 'Font Size', name: 'fontSize', type: 'number', default: 12 },
{ displayName: 'Line Spacing', name: 'lineSpacing', type: 'number', default: 1.15 },
{
displayName: 'Page-break Keyword',
name: 'pageBreakKey',
type: 'string',
default: '## Chapter',
displayOptions: { show: { operation: ['single'] } },
},
/* e-book */
{
displayName: 'Include TOC',
name: 'includeToc',
type: 'boolean',
default: true,
displayOptions: { show: { operation: ['ebook'] } },
},
{
displayName: 'TOC Title',
name: 'tocTitle',
type: 'string',
default: 'Table of Contents',
displayOptions: { show: { operation: ['ebook'], includeToc: [true] } },
},
{
displayName: 'Chapter Title Style',
name: 'chapterTitleStyle',
type: 'options',
options: [
{ name: 'New page at title', value: 'newPage' },
{ name: 'Inline', value: 'inline' },
],
default: 'newPage',
displayOptions: { show: { operation: ['ebook'] } },
},
],
};
}
async execute() {
const md = new markdown_it_1.default();
const op = this.getNodeParameter('operation', 0);
const raw = this.getNodeParameter('rawInput', 0);
const fileName = this.getNodeParameter('fileName', 0);
const font = this.getNodeParameter('font', 0);
const fontSize = this.getNodeParameter('fontSize', 0);
const lineSpacing = this.getNodeParameter('lineSpacing', 0);
/* PDF setup */
const doc = new pdfkit_1.default({ margin: 50 });
const stream = new stream_1.PassThrough();
doc.pipe(stream);
doc.font(font).fontSize(fontSize);
/* ─── SINGLE PDF ─────────────────────────────────────────────── */
if (op === 'single') {
const source = typeof raw === 'string'
? raw
: raw?.data && typeof raw.data === 'string'
? raw.data
: (() => { throw new Error('Single PDF expects string or { data }'); })();
const breakKey = this.getNodeParameter('pageBreakKey', 0);
for (const line of source.split('\n')) {
if (line.startsWith(breakKey))
doc.addPage();
doc.moveDown(lineSpacing - 1).text(md.renderInline(line), { align: 'justify' });
}
}
/* ─── E-BOOK ─────────────────────────────────────────────────── */
else {
const obj = Array.isArray(raw) ? { data: raw } : raw;
const chapters = obj?.data || (() => { throw new Error('E-book expects array or { title, data }'); })();
const bookTitle = typeof obj?.title === 'string' ? obj.title : '';
if (bookTitle) {
doc.fontSize(fontSize + 6).text(bookTitle, { align: 'center' });
doc.addPage();
}
if (this.getNodeParameter('includeToc', 0)) {
doc.fontSize(fontSize + 2)
.text(this.getNodeParameter('tocTitle', 0), { underline: true })
.moveDown();
chapters.forEach((c, i) => doc.text(`${i + 1}. ${c.title}`));
doc.addPage();
}
const titleStyle = this.getNodeParameter('chapterTitleStyle', 0);
for (const ch of chapters) {
if (titleStyle === 'newPage') {
doc.addPage();
doc.fontSize(fontSize + 4).text(ch.title, { align: 'center' });
}
else {
doc.fontSize(fontSize + 4).text(ch.title);
}
doc.moveDown().fontSize(fontSize);
for (const ln of ch.content.split('\n')) {
doc.moveDown(lineSpacing - 1).text(md.renderInline(ln), { align: 'justify' });
}
}
}
/* finalize */
doc.end();
const pdfBuffer = await (0, get_stream_1.default)(stream, { encoding: 'buffer' });
return this.prepareOutputData([{
json: {},
binary: {
data: {
data: pdfBuffer,
mimeType: 'application/pdf',
fileName, // exibido pelo n8n
fileExtension: 'pdf',
fileSize: pdfBuffer.length,
}, // `as any` evita erro de tipagem no stub
},
}]);
}
}
exports.JsonToPdf = JsonToPdf;
//# sourceMappingURL=JsonToPdf.node.js.map