simple-pdf-generator
Advanced tools
Comparing version 3.1.0 to 3.2.0
@@ -10,6 +10,6 @@ /// <reference types="node" /> | ||
includes?: Asset[]; | ||
xssProtection?: boolean; | ||
}; | ||
export declare function PdfTemplate(options: PdfTemplateOptions): (target: object) => void; | ||
export declare abstract class PdfFiller { | ||
[key: string]: unknown; | ||
private static searchRegex; | ||
@@ -16,0 +16,0 @@ fill(): Promise<Buffer>; |
@@ -12,2 +12,3 @@ "use strict"; | ||
const mime_1 = __importDefault(require("mime")); | ||
const xss_1 = __importDefault(require("xss")); | ||
function PdfField() { | ||
@@ -86,2 +87,5 @@ return function (target, propertyKey) { | ||
} | ||
if (classDecorators.options.xssProtection == null) { | ||
classDecorators.options.xssProtection = true; | ||
} | ||
let template = (await fs_1.default.promises.readFile(classDecorators.options.templatePath)).toString(); | ||
@@ -95,29 +99,29 @@ const includes = new Array(); | ||
if (((_b = match.groups) === null || _b === void 0 ? void 0 : _b['propName']) != null) { | ||
if (fieldDecorators != null) { | ||
const decorator = fieldDecorators.get(match.groups.propName); | ||
if (decorator != null) { | ||
const value = Reflect.get(this, decorator.propertyName); | ||
if (value != null) { | ||
template = template.replace(match[0], value.toString()); | ||
} | ||
} | ||
if (fieldDecorators == null) { | ||
continue; | ||
} | ||
const decorator = fieldDecorators.get(match.groups.propName); | ||
if (decorator == null) { | ||
continue; | ||
} | ||
const value = Reflect.get(this, decorator.propertyName); | ||
if (value == null) { | ||
continue; | ||
} | ||
const propValue = classDecorators.options.xssProtection ? (0, xss_1.default)(value.toString()) : value.toString(); | ||
template = template.replace(match[0], propValue); | ||
} | ||
else if (((_c = match.groups) === null || _c === void 0 ? void 0 : _c['imgSrc']) != null) { | ||
const mimeType = mime_1.default.getType(match.groups.imgSrc); | ||
if (mimeType != null) { | ||
try { | ||
let imgSrc = match.groups.imgSrc; | ||
if (!path_1.default.isAbsolute(match.groups.imgSrc)) { | ||
imgSrc = path_1.default.join(path_1.default.dirname(classDecorators.options.templatePath), match.groups.imgSrc); | ||
} | ||
const data = await fs_1.default.promises.readFile(imgSrc); | ||
const base64 = data.toString('base64'); | ||
const newSrc = `data:${mimeType};base64,${base64}`; | ||
template = template.replace(match[0], match[0].replace(match.groups.imgSrc, newSrc)); | ||
} | ||
catch (e) { | ||
console.error(e); | ||
} | ||
if (mimeType == null) { | ||
continue; | ||
} | ||
let imgSrc = match.groups.imgSrc; | ||
if (!path_1.default.isAbsolute(match.groups.imgSrc)) { | ||
imgSrc = path_1.default.join(path_1.default.dirname(classDecorators.options.templatePath), match.groups.imgSrc); | ||
} | ||
const data = await fs_1.default.promises.readFile(imgSrc); | ||
const base64 = data.toString('base64'); | ||
const newSrc = `data:${mimeType};base64,${base64}`; | ||
template = template.replace(match[0], match[0].replace(match.groups.imgSrc, newSrc)); | ||
} | ||
@@ -134,3 +138,4 @@ } | ||
let script = PdfGenerator_1.PdfGenerator.tableGeneratorScript; | ||
script = script.replace('tablesData', `tablesData = ${(0, utils_1.stringify)(tableData)}`); | ||
const tablesData = classDecorators.options.xssProtection ? (0, xss_1.default)((0, utils_1.stringify)(tableData)) : (0, utils_1.stringify)(tableData); | ||
script = script.replace('tablesData', (0, xss_1.default)(`tablesData = ${tablesData}`)); | ||
includes.push({ content: script, type: 'js' }); | ||
@@ -159,2 +164,2 @@ } | ||
exports.PdfFiller = PdfFiller; | ||
PdfFiller.searchRegex = new RegExp('(?:%%(?<propName>.*)%%)|(?:<img[^>]*src="(?<imgSrc>.*?)"[^>]*>)', 'g'); | ||
PdfFiller.searchRegex = new RegExp('(?:%%(?<propName>.*?)%%)|(?:<img[^>]*src="(?<imgSrc>.*?)"[^>]*>)', 'g'); |
@@ -19,3 +19,2 @@ /// <reference types="node" /> | ||
private static _browser; | ||
private static _browserDisconnected; | ||
private static _tableGeneratorScript; | ||
@@ -22,0 +21,0 @@ static get tableGeneratorScript(): string; |
@@ -30,8 +30,7 @@ "use strict"; | ||
}); | ||
this._browserDisconnected = false; | ||
this._browser.on('disconnected', async () => { | ||
var _a; | ||
this._browserDisconnected = true; | ||
await ((_a = this._browser) === null || _a === void 0 ? void 0 : _a.close()); | ||
(_a = this._browser) === null || _a === void 0 ? void 0 : _a.close(); | ||
this._browser = null; | ||
await this._startBrowser(); | ||
}); | ||
@@ -41,6 +40,2 @@ } | ||
var _a, _b, _c; | ||
if (this._browserDisconnected) { | ||
await new Promise((f) => setTimeout(f, 10000)); | ||
await this._startBrowser(); | ||
} | ||
if (this._browser == null) { | ||
@@ -79,2 +74,3 @@ await this._startBrowser(); | ||
static async _includeAssets(page, includes) { | ||
const promises = []; | ||
for (const include of includes) { | ||
@@ -89,18 +85,18 @@ let type = ''; | ||
if (type === 'css') { | ||
await page.addStyleTag({ | ||
promises.push(page.addStyleTag({ | ||
content: include.content, | ||
path: include.path, | ||
}); | ||
})); | ||
} | ||
else if (type === 'js') { | ||
await page.addScriptTag({ | ||
promises.push(page.addScriptTag({ | ||
content: include.content, | ||
path: include.path, | ||
}); | ||
})); | ||
} | ||
} | ||
await Promise.all(promises); | ||
} | ||
} | ||
exports.PdfGenerator = PdfGenerator; | ||
PdfGenerator._browserDisconnected = false; | ||
PdfGenerator._tableGeneratorScript = ''; |
{ | ||
"name": "simple-pdf-generator", | ||
"version": "3.1.0", | ||
"version": "3.2.0", | ||
"description": "Generator of PDF files from HTML templates using TS decorators", | ||
@@ -31,2 +31,3 @@ "main": "./lib/index.js", | ||
"@types/stringify-object": "^4.0.2", | ||
"@types/validator": "^13.11.1", | ||
"@typescript-eslint/eslint-plugin": "^6.5.0", | ||
@@ -41,3 +42,4 @@ "@typescript-eslint/parser": "^6.5.0", | ||
"mime": "^3.0.0", | ||
"puppeteer": "^21.1.1" | ||
"puppeteer": "^21.1.1", | ||
"xss": "^1.0.14" | ||
}, | ||
@@ -44,0 +46,0 @@ "scripts": { |
116
README.md
@@ -20,5 +20,5 @@ # Simple PDF Generator | ||
- supports custom CSS and JS; | ||
- fills custom fields in the HTML template; | ||
- can generate dynamic tables automatically. | ||
- supports custom CSS and JS; | ||
- fills custom fields in the HTML template; | ||
- can generate dynamic tables automatically. | ||
@@ -34,3 +34,3 @@ ## Quick Start | ||
@PdfTemplate({ | ||
templatePath: path.join(__dirname, 'template.html') | ||
templatePath: path.join(__dirname, 'template.html'), | ||
}) | ||
@@ -51,22 +51,20 @@ export class Template extends PdfFiller { | ||
<html> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>Document</title> | ||
</head> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Document</title> | ||
</head> | ||
<body> | ||
<div class="container-fluid"> | ||
<div class="container"> | ||
<div class="row justify-content-center"> | ||
<div class="col-10 text-center"> | ||
<h1>Hello %%firstField%%</h1> | ||
<h2>Welcome in %%secondField%%</h2> | ||
<body> | ||
<div class="container-fluid"> | ||
<div class="container"> | ||
<div class="row justify-content-center"> | ||
<div class="col-10 text-center"> | ||
<h1>Hello %%firstField%%</h1> | ||
<h2>Welcome in %%secondField%%</h2> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</body> | ||
</body> | ||
</html> | ||
@@ -100,6 +98,6 @@ ``` | ||
interface TableRow { | ||
index: number, | ||
name: string, | ||
surname: string, | ||
email: string | ||
index: number; | ||
name: string; | ||
surname: string; | ||
email: string; | ||
} | ||
@@ -146,3 +144,3 @@ | ||
await doc.fill(path.join(__dirname, 'doc.pdf')) | ||
await doc.fill(path.join(__dirname, 'doc.pdf')); | ||
})(); | ||
@@ -161,6 +159,3 @@ ``` | ||
templatePath: path.join(__dirname, 'template.html'), | ||
includes: [ | ||
{ path: path.join(__dirname, 'template.css') }, | ||
{ path: path.join(__dirname, 'template.js') }, | ||
] | ||
includes: [{ path: path.join(__dirname, 'template.css') }, { path: path.join(__dirname, 'template.js') }], | ||
}) | ||
@@ -182,5 +177,5 @@ export class Template extends PdfFiller { | ||
| Decorator | HTML use | | ||
|---|---| | ||
| `PdfField` | `%%propertyName%%` | | ||
| Decorator | HTML use | | ||
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `PdfField` | `%%propertyName%%` | | ||
| `PdfTable` | `<inject-table :items="propertyName">`<br> `<inject-column prop="name" label="Name"/>`<br> `<inject-column prop="surname" label="Surname"/>`<br>`</inject-table>` | | ||
@@ -192,11 +187,12 @@ | ||
| Parameter | Description | | ||
|---|---| | ||
| `outputPath: string` | PDF output dir | | ||
| Parameter | Description | | ||
| ---------------------------------- | ----------------------------------- | | ||
| `outputPath: string` | PDF output dir | | ||
| `pdfOptions: puppeteer.PDFOptions` | Object with `Puppeteer PDF Options` | | ||
PdfFiller `fill()` method accept two optional parameters: | ||
- the `outputPath` for the generated file; | ||
- the `pdfOptions` that accept `Puppeteer PDF Options`; | ||
- the `outputPath` for the generated file; | ||
- the `pdfOptions` that accept `Puppeteer PDF Options`; | ||
### `PdfTemplate` | ||
@@ -206,13 +202,14 @@ | ||
| Parameter | Description | | ||
|---|---| | ||
| `templatePath: string` | Path to the HTML file | | ||
| `pdfOptions: puppeteer.PDFOptions` | Object with `Puppeteer PDF Options` | | ||
| `includes: Asset[]` | Assets (`css` and `js`) to be included in the HTML file | | ||
| Parameter | Description | | ||
| ---------------------------------- | ------------------------------------------------------- | | ||
| `templatePath: string` | Path to the HTML file | | ||
| `pdfOptions: puppeteer.PDFOptions` | Object with `Puppeteer PDF Options` | | ||
| `xssProtection: boolean` | Enable or disable XSS protection (default: `true`) | | ||
| `includes: Asset[]` | Assets (`css` and `js`) to be included in the HTML file | | ||
```ts | ||
export interface Asset { | ||
path?: string, | ||
content?: string, | ||
type?: 'css' | 'js' | ||
path?: string; | ||
content?: string; | ||
type?: 'css' | 'js'; | ||
} | ||
@@ -242,3 +239,3 @@ ``` | ||
left: '1cm', | ||
right: '1cm' | ||
right: '1cm', | ||
}, | ||
@@ -253,6 +250,3 @@ }; | ||
templatePath: path.join(__dirname, 'template.html'), | ||
includes: [ | ||
{ path: path.join(__dirname, 'template.css') }, | ||
{ path: path.join(__dirname, 'template.js') }, | ||
], | ||
includes: [{ path: path.join(__dirname, 'template.css') }, { path: path.join(__dirname, 'template.js') }], | ||
pdfOptions: pdfOptions, | ||
@@ -284,11 +278,11 @@ }) | ||
| Environment variable | Possible values | Description | | ||
|---|---|---| | ||
| `PUPPETEER_NO_HEADLESS` | `true`, `false` | Used to run Chromium in non headless mode. | | ||
| `PUPPETEER_NO_SANDBOX` | `true`, `false` | Used to run Chromium in containers where a root user is used. | | ||
| `PUPPETEER_PRODUCT` | `chrome`, `firefox` | Specify which browser to download and use. | | ||
| `PUPPETEER_CHROMIUM_REVISION` | a chromium version | Specify a version of Chromium you’d like Puppeteer to use. | | ||
| `PUPPETEER_SKIP_CHROMIUM_DOWNLOAD` | `true`, `false` | Puppeteer will not download the bundled Chromium. You must provide `PUPPETEER_EXECUTABLE_PATH`. | | ||
| `PUPPETEER_EXECUTABLE_PATH` | a path | Specify an executable path to be used in `puppeteer.launch`. To be specified if `PUPPETEER_SKIP_CHROMIUM_DOWNLOAD` is set to `true`. | | ||
| `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY` | proxy url | Defines HTTP proxy settings that are used to download and run Chromium. | | ||
| Environment variable | Possible values | Description | | ||
| --------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | ||
| `PUPPETEER_NO_HEADLESS` | `true`, `false` | Used to run Chromium in non headless mode. | | ||
| `PUPPETEER_NO_SANDBOX` | `true`, `false` | Used to run Chromium in containers where a root user is used. | | ||
| `PUPPETEER_PRODUCT` | `chrome`, `firefox` | Specify which browser to download and use. | | ||
| `PUPPETEER_CHROMIUM_REVISION` | a chromium version | Specify a version of Chromium you’d like Puppeteer to use. | | ||
| `PUPPETEER_SKIP_CHROMIUM_DOWNLOAD` | `true`, `false` | Puppeteer will not download the bundled Chromium. You must provide `PUPPETEER_EXECUTABLE_PATH`. | | ||
| `PUPPETEER_EXECUTABLE_PATH` | a path | Specify an executable path to be used in `puppeteer.launch`. To be specified if `PUPPETEER_SKIP_CHROMIUM_DOWNLOAD` is set to `true`. | | ||
| `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY` | proxy url | Defines HTTP proxy settings that are used to download and run Chromium. | | ||
@@ -299,4 +293,4 @@ ## People | ||
- @lorenzinigiovanni [lorenzinigiovanni.com](https://www.lorenzinigiovanni.com/) | ||
- @MassimilianoMontagni [solutiontech.tech](https://www.solutiontech.tech/) | ||
- @lorenzinigiovanni [lorenzinigiovanni.com](https://www.lorenzinigiovanni.com/) | ||
- @MassimilianoMontagni [solutiontech.tech](https://www.solutiontech.tech/) | ||
@@ -303,0 +297,0 @@ ## License |
/* eslint-disable no-undef */ | ||
const tables = []; | ||
const tablesData; | ||
document.addEventListener('start', () => { | ||
createTables(); | ||
}); | ||
function createTables() { | ||
@@ -16,3 +11,2 @@ const tablesTag = [...document.getElementsByTagName('inject-table')]; | ||
const newTable = document.createElement('table'); | ||
const head = newTable.createTHead().insertRow(); | ||
@@ -39,2 +33,3 @@ const classAttribute = table.getAttribute('class'); | ||
const head = newTable.createTHead().insertRow(); | ||
for (const column of columns.values()) { | ||
@@ -56,2 +51,5 @@ const cell = document.createElement('th'); | ||
cell.innerText = column.getAttribute('label'); | ||
if (column.getAttribute('label') == null) { | ||
cell.style.display = 'none'; | ||
} | ||
@@ -62,3 +60,2 @@ head.appendChild(cell); | ||
table.replaceWith(newTable); | ||
tables.push(newTable); | ||
@@ -70,14 +67,11 @@ populateTable(newTable); | ||
function populateTable(table) { | ||
const tableFound = tables.find((documentTable) => documentTable === table); | ||
if (tableFound === undefined) return; | ||
const data = Reflect.get(tablesData, table.getAttribute('items')); | ||
const data = Reflect.get(tablesData, tableFound.getAttribute('items')); | ||
const headColumns = [...table.tHead.rows[0].cells]; | ||
const body = table.createTBody(); | ||
const headColumns = [...tableFound.tHead.rows[0].cells]; | ||
const body = tableFound.createTBody(); | ||
for (const item of data) { | ||
const newRow = body.insertRow(); | ||
headColumns.forEach(column => { | ||
headColumns.forEach((column) => { | ||
let val = Reflect.get(item, column.getAttribute('prop').split('.')[0]); | ||
@@ -87,3 +81,3 @@ if (val != null && typeof val === 'object') { | ||
let nestedVal = val; | ||
nestedProps.forEach(prop => { | ||
nestedProps.forEach((prop) => { | ||
nestedVal = Reflect.get(nestedVal, prop); | ||
@@ -90,0 +84,0 @@ }); |
29784
3
10
428
287
+ Addedxss@^1.0.14
+ Addedcommander@2.20.3(transitive)
+ Addedcssfilter@0.0.10(transitive)
+ Addedxss@1.0.15(transitive)