diff --git a/CHANGELOG.md b/CHANGELOG.md index 1de2b28..410d523 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Change Log +# [v1.2.0](https://github.com/rogerrrrrrrs/swissqrbill/compare/v1.1.0...v1.2.0) - 06.06.2020 + * Added optional callback function that gets executed once the pdf file has completed writing. + * Emit finish event once the pdf file has completed writing. + # [v1.1.0](https://github.com/rogerrrrrrrs/swissqrbill/compare/v1.0.6...v1.1.0) - 15.03.2020 * Fixed some validation checks * Improved error messages diff --git a/README.md b/README.md index bb9bc38..3342d7f 100644 --- a/README.md +++ b/README.md @@ -78,10 +78,12 @@ const data = { } }; -const pdf = new SwissQRBill.PDF(data, "qrbill.pdf"); +const pdf = new SwissQRBill.PDF(data, "qrbill.pdf", () => { + console.log("PDF has been successfully created."); +}); ``` -This will create the above PDF file. You can pass an optional third parameter that contains options like language or size etc. +This will create the above PDF file. You can pass an optional third parameter containing options such as language or size etc. as well as a callback function that gets called right after the file has finished writing. A complete documentation for all methods and parameters can be found in [doc/api.md](https://github.com/Rogerrrrrrrs/SwissQRBill/blob/master/doc/api.md).
diff --git a/doc/api.md b/doc/api.md index 5414717..faadfbf 100644 --- a/doc/api.md +++ b/doc/api.md @@ -3,22 +3,26 @@ ## Contents - Constructor - - [SwissQRBill.PDF(data, outputPath[, options])](#swissqrbillpdfdata-outputpath-options) + - [SwissQRBill.PDF(data, outputPath[, options], callback)](#swissqrbillpdfdata-outputpath-options-callback) - Methods - [addPage(options)](#addpageoptions) - [addQRBill()](#addqrbill) - [mmToPoints(mm)](#mmtopointsmm) +- Events + - [finish](#event-finish)
## Constructor -### SwissQRBill.PDF(data, outputPath[, options]) +### SwissQRBill.PDF(data, outputPath[, options], callback) - [**data**](#data) - `object` containing all relevant billing data, *mandatory*. - **outputPath** - `string` output path for the generated PDF file, *mandatory*. - [**options**](#options) - `object` containing settings, *optional*. + - **callback** - `function` that gets called right after the pdf has been created, *optional*. +> Note: The creation of the PDF file is not synchronous. You can take advantage of the callback function that gets called when the PDF is ready to interact with the created PDF file. #### data @@ -100,6 +104,7 @@ const data = { ## Methods ### addPage(options) + - options - `object` containing [PDFKit document options.](https://pdfkit.org/docs/getting_started.html#adding_pages) Adds a new page to the PDF. This method is basically the same as the original [PDFKit `addPage()` method](https://pdfkit.org/docs/getting_started.html#adding_pages). However the default values are changed to use the default page size provided in the constructor options. @@ -172,4 +177,12 @@ const table = { } ] }; -``` \ No newline at end of file +``` + +
+ +## Events + +### Event: "finish" +The finish event is emitted when the file has finished writing. +You have to wait until the file has finished writing before you are able to interact with the genereated file. \ No newline at end of file diff --git a/doc/how-to-create-a-complete-bill.md b/doc/how-to-create-a-complete-bill.md index 45cb236..a57829f 100644 --- a/doc/how-to-create-a-complete-bill.md +++ b/doc/how-to-create-a-complete-bill.md @@ -276,6 +276,8 @@ Once our document is finished, we have to call the `end()` method to finalize th pdf.end(); ``` +We also have to wait until the file has been finished writing before we are able to interact with the generated pdf file. We can do this either by passing a callback function as the last parameter to `new SwissQRBill()` or by listening for the `finish` event on the SwissQRBill instance. You can find examples using callbacks and events in [examples/callback.js](https://github.com/Rogerrrrrrrs/SwissQRBill/tree/master/examples/callback.js) and [examples/event.js](https://github.com/Rogerrrrrrrs/SwissQRBill/tree/master/examples/event.js) + The complete code can be found in [examples/how-to-create-a-complete-bill.js](https://github.com/Rogerrrrrrrs/SwissQRBill/tree/master/examples/how-to-create-a-complete-bill.js). When you run the code above, SwissQRBill should generate a PDF file name complete-qr-bill.pdf that looks like this: diff --git a/examples/callback.js b/examples/callback.js new file mode 100644 index 0000000..bc743c8 --- /dev/null +++ b/examples/callback.js @@ -0,0 +1,26 @@ +const SwissQRBill = require("swissqrbill"); + +const data = { + currency: "CHF", + amount: 1199.95, + reference: "210000000003139471430009017", + creditor: { + name: "Robert Schneider AG", + address: "Rue du Lac 1268", + zip: 2501, + city: "Biel", + account: "CH4431999123000889012", + country: "CH" + }, + debitor: { + name: "Pia-Maria Rutschmann-Schnyder", + address: "Grosse Marktgasse 28", + zip: 9400, + city: "Rorschach", + country: "CH" + } +}; + +const pdf = new SwissQRBill.PDF(data, "./output/callback.pdf", () => { + console.log("File has been successfully created."); +}); \ No newline at end of file diff --git a/examples/event.js b/examples/event.js new file mode 100644 index 0000000..3b38afa --- /dev/null +++ b/examples/event.js @@ -0,0 +1,28 @@ +const SwissQRBill = require("swissqrbill"); + +const data = { + currency: "CHF", + amount: 1199.95, + reference: "210000000003139471430009017", + creditor: { + name: "Robert Schneider AG", + address: "Rue du Lac 1268", + zip: 2501, + city: "Biel", + account: "CH4431999123000889012", + country: "CH" + }, + debitor: { + name: "Pia-Maria Rutschmann-Schnyder", + address: "Grosse Marktgasse 28", + zip: 9400, + city: "Rorschach", + country: "CH" + } +}; + +const pdf = new SwissQRBill.PDF(data, "./output/event.pdf"); + +pdf.on("finish", () => { + console.log("File has been successfully created."); +}); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 86653cb..483d66d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "swissqrbill", - "version": "1.1.0", + "version": "1.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -49,9 +49,9 @@ "dev": true }, "@types/node": { - "version": "13.11.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.11.1.tgz", - "integrity": "sha512-eWQGP3qtxwL8FGneRrC5DwrJLGN4/dH1clNTuLfN81HCrxVtxRjygDTUoZJ5ASlDEeo0ppYFQjQIlXhtXpOn6g==", + "version": "14.0.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.11.tgz", + "integrity": "sha512-lCvvI24L21ZVeIiyIUHZ5Oflv1hhHQ5E1S25IRlKIXaRkVgmXpJMI3wUJkmym2bTbCe+WoIibQnMVAU3FguaOg==", "dev": true }, "@types/pdfkit": { @@ -85,69 +85,25 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.28.0.tgz", - "integrity": "sha512-w0Ugcq2iatloEabQP56BRWJowliXUP5Wv6f9fKzjJmDW81hOTBxRoJ4LoEOxRpz9gcY51Libytd2ba3yLmSOfg==", + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", + "integrity": "sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "2.28.0", + "@typescript-eslint/experimental-utils": "2.34.0", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", "tsutils": "^3.17.1" - }, - "dependencies": { - "@typescript-eslint/experimental-utils": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.28.0.tgz", - "integrity": "sha512-4SL9OWjvFbHumM/Zh/ZeEjUFxrYKtdCi7At4GyKTbQlrj1HcphIDXlje4Uu4cY+qzszR5NdVin4CCm6AXCjd6w==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.28.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - } - }, - "@typescript-eslint/typescript-estree": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.28.0.tgz", - "integrity": "sha512-HDr8MP9wfwkiuqzRVkuM3BeDrOC4cKbO5a6BymZBHUt5y/2pL0BXD6I/C/ceq2IZoHWhcASk+5/zo+dwgu9V8Q==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "eslint-visitor-keys": "^1.1.0", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^6.3.0", - "tsutils": "^3.17.1" - } - }, - "eslint-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", - "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } } }, "@typescript-eslint/experimental-utils": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.28.0.tgz", - "integrity": "sha512-4SL9OWjvFbHumM/Zh/ZeEjUFxrYKtdCi7At4GyKTbQlrj1HcphIDXlje4Uu4cY+qzszR5NdVin4CCm6AXCjd6w==", + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", + "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.28.0", + "@typescript-eslint/typescript-estree": "2.34.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" }, @@ -164,21 +120,21 @@ } }, "@typescript-eslint/parser": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.28.0.tgz", - "integrity": "sha512-RqPybRDquui9d+K86lL7iPqH6Dfp9461oyqvlXMNtap+PyqYbkY5dB7LawQjDzot99fqzvS0ZLZdfe+1Bt3Jgw==", + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz", + "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", "dev": true, "requires": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.28.0", - "@typescript-eslint/typescript-estree": "2.28.0", + "@typescript-eslint/experimental-utils": "2.34.0", + "@typescript-eslint/typescript-estree": "2.34.0", "eslint-visitor-keys": "^1.1.0" } }, "@typescript-eslint/typescript-estree": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.28.0.tgz", - "integrity": "sha512-HDr8MP9wfwkiuqzRVkuM3BeDrOC4cKbO5a6BymZBHUt5y/2pL0BXD6I/C/ceq2IZoHWhcASk+5/zo+dwgu9V8Q==", + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", + "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", "dev": true, "requires": { "debug": "^4.1.1", @@ -186,14 +142,14 @@ "glob": "^7.1.6", "is-glob": "^4.0.1", "lodash": "^4.17.15", - "semver": "^6.3.0", + "semver": "^7.3.2", "tsutils": "^3.17.1" }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true } } @@ -2061,9 +2017,9 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "typescript": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", - "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz", + "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==", "dev": true }, "unicode-properties": { diff --git a/package.json b/package.json index b948ec0..4b6a5af 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "swissqrbill", - "version": "1.1.0", + "version": "1.2.0", "description": "Swiss QR Bill generation in node.js ", "main": "./lib/index.js", "types": "./lib/index.d.ts", @@ -34,7 +34,7 @@ "homepage": "https://github.com/Rogerrrrrrrs/SwissQRBill#readme", "devDependencies": { "@types/iban": "0.0.30", - "@types/node": "^13.9.2", + "@types/node": "^14.0.0", "@types/pdfkit": "^0.10.5", "@types/qrcode": "^1.3.4", "@types/qrcode-svg": "^1.1.0", diff --git a/src/index.ts b/src/index.ts index 5e405b1..862448d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -125,15 +125,43 @@ module SwissQRBill { * @param {data} data object containing all relevant billing data. * @param {string} outputPath string output path for the generated PDF file. * @param {options} [options] object containing settings, optional. + * @param {callback} [function] function that gets called right after the pdf has been created. * @memberof PDF * @returns an instance of SwissQRBill.PDF */ - constructor(data: data, outputPath: string, options?: options){ + constructor(data: data, outputPath: string, options?: options) + constructor(data: data, outputPath: string, options?: options, callback?: Function) + constructor(data: data, outputPath: string, callback?: Function) + constructor(data: data, outputPath: string, optionsOrCallback?: options | Function, callbackOrUndefined?: Function | undefined){ super({ autoFirstPage: false }); - super.pipe(fs.createWriteStream(outputPath)); + const stream = fs.createWriteStream(outputPath); + + super.pipe(stream); + + let callback: Function | undefined = undefined; + let options: options | undefined = undefined; + + if(typeof optionsOrCallback === "object"){ + + options = optionsOrCallback; + + if(typeof callbackOrUndefined === "function"){ + callback = callbackOrUndefined; + } + + } else if(typeof optionsOrCallback === "function"){ + callback = optionsOrCallback; + } + + stream.on("finish", ev => { + if(typeof callback === "function"){ + callback(this); + } + super.emit("finish", ev); + }); if(data === undefined || typeof data !== "object"){ throw new Error("You must provide an object as billing data."); @@ -686,7 +714,7 @@ module SwissQRBill { if(this._data.creditor.houseNumber !== undefined){ if(typeof this._data.creditor.houseNumber !== "string" && typeof this._data.creditor.houseNumber !== "number"){ throw new Error("Debitor houseNumber must be either a string or a number."); } - if(this._data.creditor.houseNumber.toString().length > 16){ throw new Error("Creditor houseNumber can be a maximum of 16 characters.");} + if(this._data.creditor.houseNumber.toString().length > 16){ throw new Error("Creditor houseNumber can be a maximum of 16 characters."); } } @@ -743,7 +771,7 @@ module SwissQRBill { if(this._data.debitor.address === undefined){ throw new Error("Debitor address cannot be undefined if the debitor object is available."); } if(typeof this._data.debitor.address !== "string"){ throw new Error("Debitor address must be a string."); } - if(this._data.debitor.address.length > 70){ throw new Error("Debitor address must be a maximum of 70 characters.");} + if(this._data.debitor.address.length > 70){ throw new Error("Debitor address must be a maximum of 70 characters."); } //-- Debitor houseNumber diff --git a/tests/callback-with-options.js b/tests/callback-with-options.js new file mode 100644 index 0000000..2e36c44 --- /dev/null +++ b/tests/callback-with-options.js @@ -0,0 +1,26 @@ +const SwissQRBill = require("../"); + +const data = { + currency: "CHF", + amount: 1199.95, + reference: "210000000003139471430009017", + creditor: { + name: "Robert Schneider AG", + address: "Rue du Lac 1268", + zip: 2501, + city: "Biel", + account: "CH4431999123000889012", + country: "CH" + }, + debitor: { + name: "Pia-Maria Rutschmann-Schnyder", + address: "Grosse Marktgasse 28", + zip: 9400, + city: "Rorschach", + country: "CH" + } +}; + +const pdf = new SwissQRBill.PDF(data, "./output/callback-with-options.pdf", { size: "A6/5" }, () => { + console.log("File has been successfully created."); +}); \ No newline at end of file diff --git a/tests/callback.js b/tests/callback.js new file mode 100644 index 0000000..9ac4058 --- /dev/null +++ b/tests/callback.js @@ -0,0 +1,26 @@ +const SwissQRBill = require("../"); + +const data = { + currency: "CHF", + amount: 1199.95, + reference: "210000000003139471430009017", + creditor: { + name: "Robert Schneider AG", + address: "Rue du Lac 1268", + zip: 2501, + city: "Biel", + account: "CH4431999123000889012", + country: "CH" + }, + debitor: { + name: "Pia-Maria Rutschmann-Schnyder", + address: "Grosse Marktgasse 28", + zip: 9400, + city: "Rorschach", + country: "CH" + } +}; + +const pdf = new SwissQRBill.PDF(data, "./output/callback.pdf", () => { + console.log("File has been successfully created."); +}); \ No newline at end of file diff --git a/tests/event.js b/tests/event.js new file mode 100644 index 0000000..c15ebda --- /dev/null +++ b/tests/event.js @@ -0,0 +1,28 @@ +const SwissQRBill = require("../"); + +const data = { + currency: "CHF", + amount: 1199.95, + reference: "210000000003139471430009017", + creditor: { + name: "Robert Schneider AG", + address: "Rue du Lac 1268", + zip: 2501, + city: "Biel", + account: "CH4431999123000889012", + country: "CH" + }, + debitor: { + name: "Pia-Maria Rutschmann-Schnyder", + address: "Grosse Marktgasse 28", + zip: 9400, + city: "Rorschach", + country: "CH" + } +}; + +const pdf = new SwissQRBill.PDF(data, "./output/event.pdf"); + +pdf.on("finish", () => { + console.log("File has been successfully created."); +}); diff --git a/tests/run-windows.bat b/tests/run-windows.bat index 81bc11f..9b5c9f4 100644 --- a/tests/run-windows.bat +++ b/tests/run-windows.bat @@ -34,4 +34,10 @@ echo "normal-iban-no-reference" echo "qr-iban" call node qr-iban echo "separate" - call node separate \ No newline at end of file + call node separate +echo "callback" + call node callback +echo "callback-with-options" + call node callback-with-options +echo "event" + call node event \ No newline at end of file diff --git a/tests/run.sh b/tests/run.sh index 4ba2545..a50758d 100644 --- a/tests/run.sh +++ b/tests/run.sh @@ -35,4 +35,10 @@ echo "normal-iban-no-reference" echo "qr-iban" node qr-iban echo "separate" - node separate \ No newline at end of file + node separate +echo "callback" + node callback +echo "callback-with-options" + node callback-with-options +echo "event" + node event \ No newline at end of file