diff --git a/.eslintrc.json b/.eslintrc.json index 051335d..e453fd1 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -111,7 +111,6 @@ "@typescript-eslint/prefer-for-of": ["error"], "@typescript-eslint/prefer-literal-enum-member": ["error"], "@typescript-eslint/prefer-readonly": ["error"], - "@typescript-eslint/prefer-readonly-parameter-types": ["error"], "@typescript-eslint/promise-function-async": ["error"], // plugin: @typescript-eslint - extension rules diff --git a/CHANGELOG.md b/CHANGELOG.md index b696566..ea65a1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.6.0] - 2023-09-17 +### Added +- New method 'process' that returns a promise for the PlantUML diagram image that is generated +### Changed +- New plantuml.jar version: V1.2023.11 (13 Sep, 2023) + ## [1.5.0] - 2023-04-10 ### Changed - Updated dependencies (split2) @@ -64,7 +70,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - First version -[Unreleased]: https://github.com/krisztianb/plantuml-pipe/compare/v1.5.0...HEAD +[Unreleased]: https://github.com/krisztianb/plantuml-pipe/compare/v1.6.0...HEAD +[1.6.0]: https://github.com/krisztianb/plantuml-pipe/releases/tag/v1.6.0 [1.5.0]: https://github.com/krisztianb/plantuml-pipe/releases/tag/v1.5.0 [1.4.0]: https://github.com/krisztianb/plantuml-pipe/releases/tag/v1.4.0 [1.3.6]: https://github.com/krisztianb/plantuml-pipe/releases/tag/v1.3.6 diff --git a/README.md b/README.md index fc3a4dd..fff8ace 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,12 @@

A PlantUmlPipe instance is a wrapper to a PlantUML JAVA process running in pipe mode. -The object has an input stream (`in`) into which the PlantUML code for one or multiple diagrams can be written and + +The object has an input stream (`in`) into which the PlantUML code of multiple diagrams can be written and an output streams (`out`) from which the generated diagrams can be read. +Instead of the streams you can also use the `process` method of the object which returns a promise with the generated diagram. + ## Installation This module can be installed using [npm](https://www.npmjs.com/package/plantuml-pipe): @@ -23,9 +26,9 @@ order to use this module. A corresponding test is run after installing this modu This module includes type definitions for TypeScript. -## Usage +## Usage (with streams) -The following TypeScript code creates two SVG image files: +The following TypeScript code creates two SVG image files using streams: ```typescript import * as fs from "fs"; @@ -54,6 +57,30 @@ Output: | :---------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------: | | ![First image](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuN8ghQfIqBLJ2C_FJwbKi588oLV8p4lBpCiigTJJqrD8p4jHI4gjpCzBKUHoICrB0Me10000) | ![Second image](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuGhFpq-fLD2rKt0ghQfIi5Bmo2y7yWk0idcfHOfS3gbvAK1b0000) | +## Usage (with promises) + +The following TypeScript code creates the same two SVG image files using promises: + +```typescript +import * as fs from "fs"; +import { PlantUmlPipe } from "plantuml_pipe"; + +const puml = new PlantUmlPipe(); + +const buzzPlantUml = "@startuml\nBuzz -> Woody : To infinity... and beyond!\n@enduml"; +const woodyPlantUml = "@startuml\nWoody -> Buzz : Howdy partner!\n@enduml"; + +puml.process(buzzPlantUml).then((imageData) => { + fs.writeFileSync("./1.svg", imageData); +}); + +puml.process(woodyPlantUml).then((imageData) => { + fs.writeFileSync("./2.svg", imageData); +}); + +puml.close(); +``` + ## Options The `PlantUmlPipe` constructor can receive an options object as a parameter. It has the following members: @@ -68,7 +95,7 @@ The `PlantUmlPipe` constructor can receive an options object as a parameter. It | `pixelCutOffValue` | To prevent memory problems PlantUML limits the width and height of pixel (PNG) graphics to 4096. Use this option to set the `PLANTUML_LIMIT_SIZE` variable which overrides this value. | | | `noErrorImages` | By default when the PlantUML process encounters an error (eg: because of an error in your PlantUML code), it still generates an image which contains an error message. You can set this option to `true` to disable error image generation. You can then implement an error handling yourself using the normal data event of PlantUMLPipe's output stream. For every error the data chunk of the event is going to start with the line `ERROR`. | `false` | | `javaOptions` | A string array of options that are passed to the JAVA process. If you are generating many big diagrams it might be necessary to increase the maximum heap size of the JAVA process. You can use this property to do so - look [here](https://plantuml.com/de/faq#e689668a91b8d065) for more information on this issue. | | -| `plantUmlArgs` | A string array of arguments that are passed to the PlantUML process as options. The PlantUML process has many options that you can set through the command line. Some of these options can be set directly using a property of the options argument you pass to the constructor of PlantUmlPipe - for example the `delimiter` property sets the `-pipedelimitor "xyz"` option. If there is no property for the option that you want to pass to the PlantUML process, you can use this property to do so. You can find the list of possible PlantUML options [here](https://plantuml.com/de/command-line#6a26f548831e6a8c). | | +| `plantUmlArgs` | A string array of arguments that are passed to the PlantUML process as options. The PlantUML process has many options that you can set through the command line. Some of these options can be set directly using a property of the options argument you pass to the constructor of PlantUmlPipe - for example the `delimiter` property sets the `-pipedelimitor "xyz"` option. If there is no property for the option that you want to pass to the PlantUML process, you can use this property to do so. You can find the list of available PlantUML options [here](https://plantuml.com/de/command-line#6a26f548831e6a8c). | | ## Bugs diff --git a/package.json b/package.json index 7d7cd78..44d46e9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plantuml-pipe", - "version": "1.5.0", + "version": "1.6.0", "description": "Generate multiple PlantUML diagrams with one JAVA process", "author": { "name": "KrisztiƔn Balla", diff --git a/src/plantuml_pipe.ts b/src/plantuml_pipe.ts index 888051d..a8ad012 100644 --- a/src/plantuml_pipe.ts +++ b/src/plantuml_pipe.ts @@ -26,6 +26,11 @@ export class PlantUmlPipe { */ private readonly outputStream: Readable; + /** + * Collection of promise resolver functions used for the "process" method that returns a promise. + */ + private readonly resolvers = new Array<(imageData: string | Readonly) => void>(); + /** * Creates a new PlantUML pipe. * @param userOptions Possible user defined options for the PlantUML generating pipe. @@ -67,4 +72,49 @@ export class PlantUmlPipe { public get out(): Readable { return this.outputStream; } + + /** + * Closes the input stream of the PlantUML diagram generator. + */ + public close(): void { + this.inputStream.end(); + } + + /** + * Resolves the currently first promise in the queue by calling its corresponding resolve function. + * @param imageData The gnerated image data that is passed to the resolve function of the promise. + */ + private readonly resolvePromise = (imageData: string | Readonly): void => { + const resolver = this.resolvers.shift(); + + if (resolver) { + resolver(imageData); + } + }; + + /** + * Generates a PlantUML diagram image from the given PlantUML code. + * @param plantUml The PlantUML code. + * @returns A promise with the data of the generated PlantUML diagram image. + */ + public async process>(plantUml: string): Promise; + public async process(plantUml: string): Promise> { + let resolver: ((imageData: string | Readonly) => void) | undefined; + + const promise = new Promise>((resolve) => { + resolver = resolve; + }); + + if (resolver) { + this.resolvers.push(resolver); + } + + if (!this.outputStream.listeners("data").includes(this.resolvePromise)) { + this.outputStream.on("data", this.resolvePromise); + } + + this.inputStream.write(plantUml.endsWith("\n") ? plantUml : plantUml + "\n"); + + return promise; + } } diff --git a/test/plantuml_pipe.test.ts b/test/plantuml_pipe.test.ts index d8b2066..ced301a 100644 --- a/test/plantuml_pipe.test.ts +++ b/test/plantuml_pipe.test.ts @@ -20,7 +20,38 @@ describe("PlantUmlPipe", function () { // eslint-disable-next-line @typescript-eslint/no-invalid-this -- See https://mochajs.org/#timeouts this.timeout(0); - it("should create two SVG images", (done) => { + it("should create two SVG images using promises", (done) => { + const puml = new PlantUmlPipe(); + + puml.process(toyStorySinglePlantUml) + .then((imageData) => { + fs.writeFileSync(__dirname + `/promise-1.svg`, imageData); + }) + .catch((err) => { + console.error("Unexpected error " + String(err)); + }); + + puml.process(toyStorySinglePlantUml) + .then((imageData) => { + fs.writeFileSync(__dirname + `/promise-2.svg`, imageData); + }) + .catch((err) => { + console.error("Unexpected error " + String(err)); + }); + + puml.out.on("close", () => { + assert.strictEqual(fs.existsSync(__dirname + "/promise-1.svg"), true); + assert.strictEqual(fs.existsSync(__dirname + "/promise-2.svg"), true); + + fs.unlinkSync(__dirname + "/promise-1.svg"); + fs.unlinkSync(__dirname + "/promise-2.svg"); + done(); + }); + + puml.close(); + }); + + it("should create two SVG images using stream events", (done) => { const puml = new PlantUmlPipe(); let fileNum = 1; diff --git a/tsconfig.json b/tsconfig.json index 6368b87..9c1e5f4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,14 +1,14 @@ { + "include": ["src"], "compilerOptions": { + "target": "es5", "lib": ["ES2015"], "module": "commonjs", "outDir": "dist", + "esModuleInterop": true, + "declaration": true, "strict": true, "noImplicitOverride": true, - "exactOptionalPropertyTypes": true, - "target": "es5", - "declaration": true, - "esModuleInterop": true - }, - "include": ["src"] + "exactOptionalPropertyTypes": true + } } diff --git a/vendor/plantuml-version.txt b/vendor/plantuml-version.txt index b531787..8a11753 100644 --- a/vendor/plantuml-version.txt +++ b/vendor/plantuml-version.txt @@ -1,2 +1,2 @@ -The plantuml.jar in this folder is: V1.2023.5 (24 Mar, 2023) +The plantuml.jar in this folder is: V1.2023.11 (13 Sep, 2023) You can find the CHANGELOG here: https://plantuml.com/changes \ No newline at end of file diff --git a/vendor/plantuml.jar b/vendor/plantuml.jar index 41da05a..67897c8 100644 Binary files a/vendor/plantuml.jar and b/vendor/plantuml.jar differ