From 7ad83a819dd13f50534c33f0ab57f60f97d8da26 Mon Sep 17 00:00:00 2001 From: Pawel Siemienik Date: Sun, 26 Jan 2020 23:56:02 +0100 Subject: [PATCH 01/10] Migration to typescript provisioning --- .babelrc | 5 -- .gitignore | 5 ++ .prettierrc | 6 ++ LICENSE | 21 +++++++ README.md | 15 +++++ package.json | 62 ++++++++++++++----- .../CellTemplateDebugPool.js | 0 src/{xls-renderer => }/CellTemplatePool.js | 0 src/{xls-renderer => }/cell/AverageCell.js | 0 src/{xls-renderer => }/cell/BaseCell.js | 0 src/{xls-renderer => }/cell/ContinueCell.js | 0 src/{xls-renderer => }/cell/DeleteCell.js | 0 src/{xls-renderer => }/cell/DumpColsCell.js | 0 src/{xls-renderer => }/cell/EndLoopCell.js | 0 src/{xls-renderer => }/cell/EndRowCell.js | 0 src/{xls-renderer => }/cell/FinishCell.js | 0 src/{xls-renderer => }/cell/ForEachCell.js | 0 src/{xls-renderer => }/cell/FormulaCell.js | 0 src/{xls-renderer => }/cell/HyperlinkCell.js | 0 src/{xls-renderer => }/cell/NormalCell.js | 0 src/{xls-renderer => }/cell/SumCell.js | 0 src/{xls-renderer => }/cell/VariableCell.js | 0 src/{xls-renderer => }/cell/WsNameCell.js | 0 tsconfig.json | 21 +++++++ tslint.json | 6 ++ 25 files changed, 119 insertions(+), 22 deletions(-) delete mode 100644 .babelrc create mode 100644 .prettierrc create mode 100644 LICENSE create mode 100644 README.md rename src/{xls-renderer-debug => }/CellTemplateDebugPool.js (100%) rename src/{xls-renderer => }/CellTemplatePool.js (100%) rename src/{xls-renderer => }/cell/AverageCell.js (100%) rename src/{xls-renderer => }/cell/BaseCell.js (100%) rename src/{xls-renderer => }/cell/ContinueCell.js (100%) rename src/{xls-renderer => }/cell/DeleteCell.js (100%) rename src/{xls-renderer => }/cell/DumpColsCell.js (100%) rename src/{xls-renderer => }/cell/EndLoopCell.js (100%) rename src/{xls-renderer => }/cell/EndRowCell.js (100%) rename src/{xls-renderer => }/cell/FinishCell.js (100%) rename src/{xls-renderer => }/cell/ForEachCell.js (100%) rename src/{xls-renderer => }/cell/FormulaCell.js (100%) rename src/{xls-renderer => }/cell/HyperlinkCell.js (100%) rename src/{xls-renderer => }/cell/NormalCell.js (100%) rename src/{xls-renderer => }/cell/SumCell.js (100%) rename src/{xls-renderer => }/cell/VariableCell.js (100%) rename src/{xls-renderer => }/cell/WsNameCell.js (100%) create mode 100644 tsconfig.json create mode 100644 tslint.json diff --git a/.babelrc b/.babelrc deleted file mode 100644 index f9237a3..0000000 --- a/.babelrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "presets": [ - "es2017-node7" - ] -} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 09a5799..ee8202e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,10 @@ /lib /node_modules /.idea +/coverage/ +/.nyc_output/ +/.idea/ + + /src/example.js *.xlsx \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..6384a62 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "printWidth": 120, + "trailingComma": "all", + "singleQuote": true, + "tabWidth": 4 +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2c47e72 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Siemienik Paweł + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..60a7d29 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +![GitHub Workflow Status](https://img.shields.io/github/workflow/status/siemienik/xlsx-renderer/lint-build-test)![NPM](https://img.shields.io/npm/l/xlsx-renderer)![npm](https://img.shields.io/npm/v/xlsx-renderer) +![Snyk Vulnerabilities for GitHub Repo](https://img.shields.io/snyk/vulnerabilities/github/siemienik/xlsx-renderer)![GitHub top language](https://img.shields.io/github/languages/top/siemienik/xlsx-renderer)![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/siemienik/xlsx-renderer) + +# Getting Started: + +1. install package + +``` +npm i xlsx-renderer --save +``` + +2. todo some instruction how to use it + + +[LICENSE](LICENSE) \ No newline at end of file diff --git a/package.json b/package.json index 52ea898..44b3d37 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,53 @@ { - "name": "xls-renderer", - "version": "1.1.2", + "name": "xlsx-renderer", + "version": "1.1.2", "description": "Allows render xlsx files based on template supplied by viewModel.", - "main": "index.js", - "scripts": { - "postinstall": "babel src --out-dir lib --copy-files", - "example": "node lib/example.js", - "build": "node_modules/.bin/babel -d lib -s true src ", - "watch": "node_modules/.bin/babel -d lib -s true src --watch", - "test": "echo \"Error: no test specified\" && exit 1" - }, + "main": "lib/Renderer.js", + "types": "lib/Renderer.d.ts", "author": "Paweł Siemienik ", - "devDependencies": { - "babel-cli": "^6.26.0", - "babel-preset-es2015": "^6.24.1", - "babel-preset-es2017-node7": "^0.5.2" - }, "directories": { "lib": "lib/" }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/Siemienik/xlsx-renderer" + }, + "keywords": [ + "excel", + "xlsx", + "rendering xlsx", + "generator", + "template" + ], + "scripts": { + "build": "tsc", + "format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"", + "lint": "tslint -p tsconfig.json", + "test": "mocha -r ts-node/register tests/**/*.test.ts", + "coverageRaport": "nyc -r lcov -e .ts -x \"*.test.ts\" mocha -r ts-node/register tests/**/*.test.ts && nyc report", + "prepublishOnly": "npm test && npm run lint && npm run build", + "preversion": "npm run lint", + "version": "npm run format && git add -A src", + "postversion": "git push && git push --tags" + }, + "devDependencies": { + "@types/chai": "^4.1.7", + "@types/mocha": "^5.2.6", + "chai": "^4.2.0", + "mocha": "^6.1.4", + "nyc": "^14.0.0", + "prettier": "^1.17.0", + "ts-node": "^8.1.0", + "tslint": "^5.16.0", + "tslint-config-prettier": "^1.18.0", + "typescript": "^3.4.4" + }, "dependencies": { - "exceljs": "github:p3rio/exceljs#build" - } + "exceljs": "^3.6.1" + }, + "files": [ + "lib/**/*" + ] } + diff --git a/src/xls-renderer-debug/CellTemplateDebugPool.js b/src/CellTemplateDebugPool.js similarity index 100% rename from src/xls-renderer-debug/CellTemplateDebugPool.js rename to src/CellTemplateDebugPool.js diff --git a/src/xls-renderer/CellTemplatePool.js b/src/CellTemplatePool.js similarity index 100% rename from src/xls-renderer/CellTemplatePool.js rename to src/CellTemplatePool.js diff --git a/src/xls-renderer/cell/AverageCell.js b/src/cell/AverageCell.js similarity index 100% rename from src/xls-renderer/cell/AverageCell.js rename to src/cell/AverageCell.js diff --git a/src/xls-renderer/cell/BaseCell.js b/src/cell/BaseCell.js similarity index 100% rename from src/xls-renderer/cell/BaseCell.js rename to src/cell/BaseCell.js diff --git a/src/xls-renderer/cell/ContinueCell.js b/src/cell/ContinueCell.js similarity index 100% rename from src/xls-renderer/cell/ContinueCell.js rename to src/cell/ContinueCell.js diff --git a/src/xls-renderer/cell/DeleteCell.js b/src/cell/DeleteCell.js similarity index 100% rename from src/xls-renderer/cell/DeleteCell.js rename to src/cell/DeleteCell.js diff --git a/src/xls-renderer/cell/DumpColsCell.js b/src/cell/DumpColsCell.js similarity index 100% rename from src/xls-renderer/cell/DumpColsCell.js rename to src/cell/DumpColsCell.js diff --git a/src/xls-renderer/cell/EndLoopCell.js b/src/cell/EndLoopCell.js similarity index 100% rename from src/xls-renderer/cell/EndLoopCell.js rename to src/cell/EndLoopCell.js diff --git a/src/xls-renderer/cell/EndRowCell.js b/src/cell/EndRowCell.js similarity index 100% rename from src/xls-renderer/cell/EndRowCell.js rename to src/cell/EndRowCell.js diff --git a/src/xls-renderer/cell/FinishCell.js b/src/cell/FinishCell.js similarity index 100% rename from src/xls-renderer/cell/FinishCell.js rename to src/cell/FinishCell.js diff --git a/src/xls-renderer/cell/ForEachCell.js b/src/cell/ForEachCell.js similarity index 100% rename from src/xls-renderer/cell/ForEachCell.js rename to src/cell/ForEachCell.js diff --git a/src/xls-renderer/cell/FormulaCell.js b/src/cell/FormulaCell.js similarity index 100% rename from src/xls-renderer/cell/FormulaCell.js rename to src/cell/FormulaCell.js diff --git a/src/xls-renderer/cell/HyperlinkCell.js b/src/cell/HyperlinkCell.js similarity index 100% rename from src/xls-renderer/cell/HyperlinkCell.js rename to src/cell/HyperlinkCell.js diff --git a/src/xls-renderer/cell/NormalCell.js b/src/cell/NormalCell.js similarity index 100% rename from src/xls-renderer/cell/NormalCell.js rename to src/cell/NormalCell.js diff --git a/src/xls-renderer/cell/SumCell.js b/src/cell/SumCell.js similarity index 100% rename from src/xls-renderer/cell/SumCell.js rename to src/cell/SumCell.js diff --git a/src/xls-renderer/cell/VariableCell.js b/src/cell/VariableCell.js similarity index 100% rename from src/xls-renderer/cell/VariableCell.js rename to src/cell/VariableCell.js diff --git a/src/xls-renderer/cell/WsNameCell.js b/src/cell/WsNameCell.js similarity index 100% rename from src/xls-renderer/cell/WsNameCell.js rename to src/cell/WsNameCell.js diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..b626526 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "declaration": true, + "outDir": "./lib", + "strict": true, + "esModuleInterop": true, + "sourceMap": true, + "lib": [ + "es2015" + ] + }, + "include": [ + "src" + ], + "exclude": [ + "node_modules", + "tests" + ] +} \ No newline at end of file diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..71287e5 --- /dev/null +++ b/tslint.json @@ -0,0 +1,6 @@ +{ + "extends": [ + "tslint:recommended", + "tslint-config-prettier" + ] +} \ No newline at end of file From 67f46a5d8ac168e5339e853b4aa6c4fc0127c06a Mon Sep 17 00:00:00 2001 From: Pawel Siemienik Date: Mon, 27 Jan 2020 00:00:39 +0100 Subject: [PATCH 02/10] WIP: #2 First TS classes, work stopped because of the necessary fixes in the `ExcelJS` library: https://github.com/exceljs/exceljs/pull/1092 --- src/Renderer.ts | 22 +++++ src/Scope.ts | 116 +++++++++++++++++++++++++ src/xls-renderer/Renderer.js | 39 --------- src/xls-renderer/Scope.js | 161 ----------------------------------- 4 files changed, 138 insertions(+), 200 deletions(-) create mode 100644 src/Renderer.ts create mode 100644 src/Scope.ts delete mode 100644 src/xls-renderer/Renderer.js delete mode 100644 src/xls-renderer/Scope.js diff --git a/src/Renderer.ts b/src/Renderer.ts new file mode 100644 index 0000000..4f46fc5 --- /dev/null +++ b/src/Renderer.ts @@ -0,0 +1,22 @@ +import Scope from "./Scope"; +import CellTemplatePool from "./CellTemplatePool" +import {Workbook} from "exceljs"; + +export default class Renderer { + constructor(private cellTemplatePool: CellTemplatePool = new CellTemplatePool) { + } + + + async render(templateFactory: () => Workbook, vm: any): Promise { + const template = await templateFactory(); + const output = await templateFactory(); + + const scope = new Scope(template, output, vm); + + while (!scope.isFinished()) { + this.cellTemplatePool.match(scope.getCurrentTemplateCell()).apply(scope); + } + + return output; + } +} \ No newline at end of file diff --git a/src/Scope.ts b/src/Scope.ts new file mode 100644 index 0000000..e63fc74 --- /dev/null +++ b/src/Scope.ts @@ -0,0 +1,116 @@ +import {Address, Cell, CellValue, Workbook} from "exceljs"; + +export interface CellCoord { + r: number; + c: number; + ws: number; +} + +export default class Scope { + + public output_cell: CellCoord = Object.freeze({r: 1, c: 1, ws: 0}); + + public template_cell: CellCoord = Object.freeze({r: 1, c: 1, ws: 0}); + + private _masters: { [id: string]: Address; } = {}; + + private _frozen: number = 0; + + private _finished: boolean = false; + + constructor(public template: Workbook, public output: Workbook, public vm: any) { + } + + public getCurrentTemplateValue(): CellValue { + return this.getCurrentTemplateCell().value; + } + + getCurrentTemplateCell(): Cell { + return this.template.worksheets[this.template_cell.ws].getCell(this.template_cell.r, this.template_cell.c); + } + + setCurrentOutputValue(value: CellValue) { + if (this._frozen) { + return; + } + this.output.worksheets[this.output_cell.ws].getCell(this.output_cell.r, this.output_cell.c).value = value; + } + + applyStyles() { + if (this._frozen) { + return; + } + const ct = this.template_cell; + const wst = this.template.worksheets[ct.ws]; + const co = this.output_cell; + const wso = this.output.worksheets[co.ws]; + wso.getRow(co.r).height = wst.getRow(ct.r).height; + wso.getCell(co.r, co.c).style = wst.getCell(ct.r, ct.c).style; + if (wst.getColumn(ct.c).isCustomWidth) { + wso.getColumn(co.c).width = wst.getColumn(ct.c).width; + } + } + + applyMerge() { + const tws = this.template.worksheets[this.template_cell.ws]; + const tc = tws.getCell(this.template_cell.r, this.template_cell.c); + + const ows = this.output.worksheets[this.output_cell.ws]; + const current = ows.getCell(this.output_cell.r, this.output_cell.c).model.address; + + if (tc.model.master && tc.model.master !== tc.address) { + const range = `${this._masters[tc.model.master] || tc.model.master}:${current}`; + + ows.unMergeCells(range); + ows.mergeCells(range); + } else if (tc.isMerged) { + this._masters[tc.address] = current; + } + } + + incrementCol() { + if (!this._finished) { + this.template_cell = Object.freeze({...this.template_cell, c: this.template_cell.c + 1}); + } + + this.output_cell = Object.freeze({...this.output_cell, c: this.output_cell.c + 1}); + } + + incrementRow() { + if (!this._finished) { + this.template_cell = Object.freeze({...this.template_cell, r: this.template_cell.r + 1, c: 1}); + } + + if (this._frozen) { + this.output.worksheets[this.output_cell.ws].spliceRows(this.output_cell.r + 1, 1); //todo refactoring + this.output_cell = Object.freeze({...this.output_cell, c: 1}) + } else { + this.output_cell = Object.freeze({...this.output_cell, r: this.output_cell.r + 1, c: 1}) + } + } + + freezeOutput() { + this._frozen++; + } + + unfreezeOutput() { + this._frozen = Math.max(this._frozen - 1, 0); + } + + /** + * @returns {boolean} + */ + isFrozen() { + return this._frozen > 0; + } + + finish() { + this._finished = true; + this.unfreezeOutput(); + } + + isFinished() { + return this._finished; + } + +} diff --git a/src/xls-renderer/Renderer.js b/src/xls-renderer/Renderer.js deleted file mode 100644 index 1915410..0000000 --- a/src/xls-renderer/Renderer.js +++ /dev/null @@ -1,39 +0,0 @@ -import Scope from "./Scope"; -import CellTemplatePool from "./CellTemplatePool" - -export default class Renderer { - /** - * @var {CellTemplatePool} - */ - _cellTemplatePool; - /** - * @param {CellTemplatePool} cellTemplatePool - */ - constructor(cellTemplatePool) { - if (!cellTemplatePool instanceof CellTemplatePool) { - throw new TypeError(`parameter 'cellTemplatePool' has to be instance of ${CellTemplatePool.name}`); - } - - this._cellTemplatePool = cellTemplatePool; - } - - - /** - * @param {()=Workbook} templateFactory - * @param {Object} vm - * - * @returns {Workbook} output file - */ - async render(templateFactory, vm) { - const template = await templateFactory(); - const output = await templateFactory(); - - const scope = new Scope(template, output, vm); - - while (!scope.isFinished()) { - this._cellTemplatePool.match(scope.getCurrentTemplateCell()).apply(scope); - } - - return output; - } -} \ No newline at end of file diff --git a/src/xls-renderer/Scope.js b/src/xls-renderer/Scope.js deleted file mode 100644 index 6e282f6..0000000 --- a/src/xls-renderer/Scope.js +++ /dev/null @@ -1,161 +0,0 @@ -export default class Scope { - - /** - * @var {Workbook} - */ - template; - - /** - * @var {Workbook} - */ - output; - - /** - * @var {{}} view model - */ - vm; - - /** - * @var {{r:int, c:int}} - */ - output_cell = Object.freeze({r: 1, c: 1, ws: 0}); - - /** - * @var {{r:int, c:int}} - */ - template_cell = Object.freeze({r: 1, c: 1, ws: 0}); - - /** - * @var {Object.} - */ - _masters = {}; - - /** - * @var {int} - * @private - */ - _frozen = 0; - - /** - * @var {boolean} - * - * @private - */ - _finished = false; - - /** - * @param {Workbook} template - * @param {Workbook} output - * - * @param {Object} vm - */ - constructor(template, output, vm) { - this.template = template; - this.output = output; - this.vm = vm; - } - - /** - * @returns {string|Object} - */ - getCurrentTemplateValue() { - return this.getCurrentTemplateCell().value; - } - - /** - * @returns {Cell} - */ - getCurrentTemplateCell() { - return this.template.worksheets[this.template_cell.ws].getCell(this.template_cell.r, this.template_cell.c); - } - - /** - * @param {?string|{formula:string}|{text:string,hyperlink:string}} value - */ - setCurrentOutputValue(value) { - if (!this._frozen) { - // noinspection JSValidateTypes - todo exceljs invalid type definition todo - this.output.worksheets[this.output_cell.ws].getCell(this.output_cell.r, this.output_cell.c).value = value; - } - } - - applyStyles() { - if (!this._frozen) { - const ct = this.template_cell; - const wst = this.template.worksheets[ct.ws]; - - const co = this.output_cell; - const wso = this.output.worksheets[co.ws]; //todo refactoring - - wso.getRow(co.r).height = wst.getRow(ct.r).height; - wso.getCell(co.r, co.c).style = wst.getCell(ct.r, ct.c).style; - - if (wst.getColumn(ct.c).isCustomWidth) { - wso.getColumn(co.c).width = wst.getColumn(ct.c).width; - } - } - } - - applyMerge() { - const tws = this.template.worksheets[this.template_cell.ws]; - const tc = tws.getCell(this.template_cell.r, this.template_cell.c); - - const ows = this.output.worksheets[this.output_cell.ws]; - const current = ows.getCell(this.output_cell.r, this.output_cell.c).model.address; - - if (tc.model.master && tc.model.master !== tc.model.address) { - const range = `${this._masters[tc.model.master] || tc.model.master}:${current}`; - - ows.unMergeCells(range); - ows.mergeCells(range); - } else if (tc.isMerged) { - this._masters[tc.model.address] = current; - } - } - - incrementCol() { - if (!this._finished) { - this.template_cell = Object.freeze({...this.template_cell, c: this.template_cell.c + 1}); - } - - this.output_cell = Object.freeze({...this.output_cell, c: this.output_cell.c + 1}); - } - - incrementRow() { - if (!this._finished) { - this.template_cell = Object.freeze({...this.template_cell, r: this.template_cell.r + 1, c: 1}); - } - - if (this._frozen) { - this.output.worksheets[this.output_cell.ws].spliceRows(this.output_cell.r + 1, 1); //todo refactoring - this.output_cell = Object.freeze({...this.output_cell, c: 1}) - } else { - this.output_cell = Object.freeze({...this.output_cell, r: this.output_cell.r + 1, c: 1}) - } - } - - freezeOutput() { - this._frozen++; - } - - unfreezeOutput() { - this._frozen = Math.max(this._frozen - 1, 0); - } - - /** - * @returns {boolean} - */ - isFrozen() { - return this._frozen > 0; - } - - finish() { - this._finished = true; - this.unfreezeOutput(); - } - - isFinished() { - return this._finished; - } - -} From dd8913ff43bb3c64540393e7ed9e028fdf2010a6 Mon Sep 17 00:00:00 2001 From: Pawel Siemienik Date: Mon, 27 Jan 2020 02:36:03 +0100 Subject: [PATCH 03/10] WIP: #2 Setup tests (#3) , lint files and 3 additional ts files migrated from js --- package.json | 2 +- src/CellTemplatePool.js | 74 -------------------------------- src/CellTemplatePool.ts | 56 ++++++++++++++++++++++++ src/Renderer.ts | 16 +++---- src/Scope.ts | 92 ++++++++++++++++++++-------------------- src/cell/AverageCell.js | 4 +- src/cell/BaseCell.js | 44 ------------------- src/cell/BaseCell.ts | 29 +++++++++++++ src/cell/DumpColsCell.js | 2 +- src/cell/EndLoopCell.js | 4 +- src/cell/FinishCell.js | 18 ++++---- src/cell/ForEachCell.js | 14 +++--- src/cell/FormulaCell.js | 2 +- src/cell/NormalCell.js | 29 ------------- src/cell/NormalCell.ts | 33 ++++++++++++++ src/cell/SumCell.js | 4 +- src/cell/VariableCell.js | 2 +- src/cell/WsNameCell.js | 4 +- tests/Renderer.test.ts | 12 ++++++ tslint.json | 6 ++- 20 files changed, 216 insertions(+), 231 deletions(-) delete mode 100644 src/CellTemplatePool.js create mode 100644 src/CellTemplatePool.ts delete mode 100644 src/cell/BaseCell.js create mode 100644 src/cell/BaseCell.ts delete mode 100644 src/cell/NormalCell.js create mode 100644 src/cell/NormalCell.ts create mode 100644 tests/Renderer.test.ts diff --git a/package.json b/package.json index 44b3d37..76e9b89 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ ], "scripts": { "build": "tsc", - "format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"", + "format": "prettier --write \"src/**/*.ts\"", "lint": "tslint -p tsconfig.json", "test": "mocha -r ts-node/register tests/**/*.test.ts", "coverageRaport": "nyc -r lcov -e .ts -x \"*.test.ts\" mocha -r ts-node/register tests/**/*.test.ts && nyc report", diff --git a/src/CellTemplatePool.js b/src/CellTemplatePool.js deleted file mode 100644 index f5bd17f..0000000 --- a/src/CellTemplatePool.js +++ /dev/null @@ -1,74 +0,0 @@ -import VariableCell from "./cell/VariableCell"; -import NormalCell from "./cell/NormalCell"; -import FinishCell from "./cell/FinishCell"; -import ForEachCell from "./cell/ForEachCell"; -import ContinueCell from "./cell/ContinueCell"; -import EndLoopCell from "./cell/EndLoopCell"; -import EndRowCell from "./cell/EndRowCell"; -import SumCell from "./cell/SumCell"; -import AverageCell from "./cell/AverageCell"; -import DeleteCell from "./cell/DeleteCell"; -import DumpColsCell from "./cell/DumpColsCell"; -import WsNameCell from "./cell/WsNameCell"; -import HyperlinkCell from "./cell/HyperlinkCell"; -import FormulaCell from "./cell/FormulaCell"; - -export default class CellTemplatePool { - /** - * @type {*[]} - * @private - */ - _cells = [ - NormalCell, - EndRowCell, - VariableCell, - FormulaCell, - HyperlinkCell, - ForEachCell, - FinishCell, - EndLoopCell, - ContinueCell, - DumpColsCell, - SumCell, - AverageCell, - WsNameCell, - DeleteCell, - ]; - - /** - * @type {{}} - * @private - */ - _instances = {}; - - /** - * @param {Cell} cell - * @returns {BaseCell} - */ - match(cell) { - const type = this._cells.find((x) => x.match(cell)); - - return type ? this._getInstance(type) : this._getInstance(NormalCell); - } - - /** - * - * @param {Function} type Class - * @returns {BaseCell} - * @private - */ - _getInstance(type) { - - if (!this._cells.includes(type)) { - throw new TypeError(`parameter 'type' has to included in [${this._cells.map((x) => x.name)}]`); - } - - if (!this._instances[type.name]) { - this._instances[type.name] = new type(); - } - - - return this._instances[type.name]; - - } -} diff --git a/src/CellTemplatePool.ts b/src/CellTemplatePool.ts new file mode 100644 index 0000000..1f67846 --- /dev/null +++ b/src/CellTemplatePool.ts @@ -0,0 +1,56 @@ +import { Cell } from 'exceljs'; + +import { BaseCell, CellType } from './cell/BaseCell'; +import { NormalCell } from './cell/NormalCell'; +// import VariableCell from "./cell/VariableCell"; +// import FinishCell from "./cell/FinishCell"; +// import ForEachCell from "./cell/ForEachCell"; +// import ContinueCell from "./cell/ContinueCell"; +// import EndLoopCell from "./cell/EndLoopCell"; +// import EndRowCell from "./cell/EndRowCell"; +// import SumCell from "./cell/SumCell"; +// import AverageCell from "./cell/AverageCell"; +// import DeleteCell from "./cell/DeleteCell"; +// import DumpColsCell from "./cell/DumpColsCell"; +// import WsNameCell from "./cell/WsNameCell"; +// import HyperlinkCell from "./cell/HyperlinkCell"; +// import FormulaCell from "./cell/FormulaCell"; + +export class CellTemplatePool { + protected cells: CellType[] = [ + NormalCell, + // EndRowCell, + // VariableCell, + // FormulaCell, + // HyperlinkCell, + // ForEachCell, + // FinishCell, + // EndLoopCell, + // ContinueCell, + // DumpColsCell, + // SumCell, + // AverageCell, + // WsNameCell, + // DeleteCell, + ]; + + protected instances: { [key: string]: BaseCell } = {}; + + public match(cell: Cell): BaseCell { + const type = this.cells.find(x => x.match(cell)); + + return type ? this.getInstance(type) : this.getInstance(NormalCell); + } + + private getInstance(type: CellType): BaseCell { + if (!this.cells.includes(type)) { + throw new TypeError(`parameter 'type' has to included in [${this.cells.map(x => x.name)}]`); + } + + if (!this.instances[type.name]) { + this.instances[type.name] = new type(); + } + + return this.instances[type.name]; + } +} diff --git a/src/Renderer.ts b/src/Renderer.ts index 4f46fc5..587eebe 100644 --- a/src/Renderer.ts +++ b/src/Renderer.ts @@ -1,13 +1,13 @@ -import Scope from "./Scope"; -import CellTemplatePool from "./CellTemplatePool" -import {Workbook} from "exceljs"; +import { Workbook } from 'exceljs'; -export default class Renderer { - constructor(private cellTemplatePool: CellTemplatePool = new CellTemplatePool) { - } +import { Scope } from './Scope'; +import { CellTemplatePool } from './CellTemplatePool'; +export class Renderer { + constructor(private cellTemplatePool: CellTemplatePool = new CellTemplatePool()) { + } - async render(templateFactory: () => Workbook, vm: any): Promise { + public async render(templateFactory: () => Workbook, vm: any): Promise { const template = await templateFactory(); const output = await templateFactory(); @@ -19,4 +19,4 @@ export default class Renderer { return output; } -} \ No newline at end of file +} diff --git a/src/Scope.ts b/src/Scope.ts index e63fc74..7322fdf 100644 --- a/src/Scope.ts +++ b/src/Scope.ts @@ -1,22 +1,21 @@ -import {Address, Cell, CellValue, Workbook} from "exceljs"; +import { Address, Cell, CellValue, Workbook } from 'exceljs'; -export interface CellCoord { +export interface ICellCoord { r: number; c: number; ws: number; } -export default class Scope { +export class Scope { + public outputCell: ICellCoord = Object.freeze({ r: 1, c: 1, ws: 0 }); - public output_cell: CellCoord = Object.freeze({r: 1, c: 1, ws: 0}); + public templateCell: ICellCoord = Object.freeze({ r: 1, c: 1, ws: 0 }); - public template_cell: CellCoord = Object.freeze({r: 1, c: 1, ws: 0}); + private masters: { [id: string]: Address } = {}; - private _masters: { [id: string]: Address; } = {}; + private frozen: number = 0; - private _frozen: number = 0; - - private _finished: boolean = false; + private finished: boolean = false; constructor(public template: Workbook, public output: Workbook, public vm: any) { } @@ -25,24 +24,24 @@ export default class Scope { return this.getCurrentTemplateCell().value; } - getCurrentTemplateCell(): Cell { - return this.template.worksheets[this.template_cell.ws].getCell(this.template_cell.r, this.template_cell.c); + public getCurrentTemplateCell(): Cell { + return this.template.worksheets[this.templateCell.ws].getCell(this.templateCell.r, this.templateCell.c); } - setCurrentOutputValue(value: CellValue) { - if (this._frozen) { + public setCurrentOutputValue(value: CellValue) { + if (this.frozen) { return; } - this.output.worksheets[this.output_cell.ws].getCell(this.output_cell.r, this.output_cell.c).value = value; + this.output.worksheets[this.outputCell.ws].getCell(this.outputCell.r, this.outputCell.c).value = value; } - applyStyles() { - if (this._frozen) { + public applyStyles() { + if (this.frozen) { return; } - const ct = this.template_cell; + const ct = this.templateCell; const wst = this.template.worksheets[ct.ws]; - const co = this.output_cell; + const co = this.outputCell; const wso = this.output.worksheets[co.ws]; wso.getRow(co.r).height = wst.getRow(ct.r).height; wso.getCell(co.r, co.c).style = wst.getCell(ct.r, ct.c).style; @@ -51,66 +50,65 @@ export default class Scope { } } - applyMerge() { - const tws = this.template.worksheets[this.template_cell.ws]; - const tc = tws.getCell(this.template_cell.r, this.template_cell.c); + public applyMerge() { + const tws = this.template.worksheets[this.templateCell.ws]; + const tc = tws.getCell(this.templateCell.r, this.templateCell.c); - const ows = this.output.worksheets[this.output_cell.ws]; - const current = ows.getCell(this.output_cell.r, this.output_cell.c).model.address; + const ows = this.output.worksheets[this.outputCell.ws]; + const current = ows.getCell(this.outputCell.r, this.outputCell.c).model.address; if (tc.model.master && tc.model.master !== tc.address) { - const range = `${this._masters[tc.model.master] || tc.model.master}:${current}`; + const range = `${this.masters[tc.model.master] || tc.model.master}:${current}`; ows.unMergeCells(range); ows.mergeCells(range); } else if (tc.isMerged) { - this._masters[tc.address] = current; + this.masters[tc.address] = current; } } - incrementCol() { - if (!this._finished) { - this.template_cell = Object.freeze({...this.template_cell, c: this.template_cell.c + 1}); + public incrementCol() { + if (!this.finished) { + this.templateCell = Object.freeze({ ...this.templateCell, c: this.templateCell.c + 1 }); } - this.output_cell = Object.freeze({...this.output_cell, c: this.output_cell.c + 1}); + this.outputCell = Object.freeze({ ...this.outputCell, c: this.outputCell.c + 1 }); } - incrementRow() { - if (!this._finished) { - this.template_cell = Object.freeze({...this.template_cell, r: this.template_cell.r + 1, c: 1}); + public incrementRow() { + if (!this.finished) { + this.templateCell = Object.freeze({ ...this.templateCell, r: this.templateCell.r + 1, c: 1 }); } - if (this._frozen) { - this.output.worksheets[this.output_cell.ws].spliceRows(this.output_cell.r + 1, 1); //todo refactoring - this.output_cell = Object.freeze({...this.output_cell, c: 1}) + if (this.frozen) { + this.output.worksheets[this.outputCell.ws].spliceRows(this.outputCell.r + 1, 1); // todo refactoring + this.outputCell = Object.freeze({ ...this.outputCell, c: 1 }); } else { - this.output_cell = Object.freeze({...this.output_cell, r: this.output_cell.r + 1, c: 1}) + this.outputCell = Object.freeze({ ...this.outputCell, r: this.outputCell.r + 1, c: 1 }); } } - freezeOutput() { - this._frozen++; + public freezeOutput() { + this.frozen++; } - unfreezeOutput() { - this._frozen = Math.max(this._frozen - 1, 0); + public unfreezeOutput() { + this.frozen = Math.max(this.frozen - 1, 0); } /** * @returns {boolean} */ - isFrozen() { - return this._frozen > 0; + public isFrozen() { + return this.frozen > 0; } - finish() { - this._finished = true; + public finish() { + this.finished = true; this.unfreezeOutput(); } - isFinished() { - return this._finished; + public isFinished() { + return this.finished; } - } diff --git a/src/cell/AverageCell.js b/src/cell/AverageCell.js index 7c2f0e1..7476b8c 100644 --- a/src/cell/AverageCell.js +++ b/src/cell/AverageCell.js @@ -15,8 +15,8 @@ export default class AverageCell extends BaseCell { const __endOutput = scope.vm[target] && scope.vm[target].__endOutput; if (__startOutput && __endOutput) { - const start = scope.output.worksheets[scope.output_cell.ws].getCell(__startOutput, scope.output_cell.c).address; //todo refactoring - const end = scope.output.worksheets[scope.output_cell.ws].getCell(__endOutput, scope.output_cell.c).address; //todo refactoring + const start = scope.output.worksheets[scope.outputCell.ws].getCell(__startOutput, scope.outputCell.c).address; //todo refactoring + const end = scope.output.worksheets[scope.outputCell.ws].getCell(__endOutput, scope.outputCell.c).address; //todo refactoring scope.setCurrentOutputValue({formula: `average(${start}:${end})`}); } diff --git a/src/cell/BaseCell.js b/src/cell/BaseCell.js deleted file mode 100644 index ab119ba..0000000 --- a/src/cell/BaseCell.js +++ /dev/null @@ -1,44 +0,0 @@ -import Scope from '../Scope' - -/** - * @abstract - */ -class BaseCell { - constructor() { - if (new.target === BaseCell) { - throw new TypeError(`Cannot construct ${BaseCell.name} instances directly. It's abstract.`); - } - } - - /** - * - * @param {Scope} scope - * @returns {BaseCell} - */ - apply(scope) { - if (!scope instanceof Scope) { - throw new TypeError(`'scope' parameter has to be instance of ${Scope.name}`); - } - if (scope.output_cell.c > 16384) { - scope.output_cell = Object.freeze({...scope.output_cell, c: 16384}); - } - scope.setCurrentOutputValue(scope.getCurrentTemplateValue()); - scope.applyStyles(); - scope.applyMerge(); - - return this; - } - - /** - * check if this commend can parse `value` - * - * @param {Cell} cell - * @returns {boolean} - */ - static match(cell) { - return false; - } - -} - -export default BaseCell \ No newline at end of file diff --git a/src/cell/BaseCell.ts b/src/cell/BaseCell.ts new file mode 100644 index 0000000..9277687 --- /dev/null +++ b/src/cell/BaseCell.ts @@ -0,0 +1,29 @@ +import { Cell } from 'exceljs'; + +import { Scope } from '../Scope'; + +export declare type CellType = typeof BaseCell; + +export class BaseCell { + /** + * check if this commend can parse `value` + */ + public static match(cell: Cell) { + return false; + } + + public BaseCell() { + throw new TypeError(`Cannot construct ${BaseCell.name} instances directly. It's abstract.`); + } + + public apply(scope: Scope) { + if (scope.outputCell.c > 16384) { + scope.outputCell = Object.freeze({ ...scope.outputCell, c: 16384 }); + } + scope.setCurrentOutputValue(scope.getCurrentTemplateValue()); + scope.applyStyles(); + scope.applyMerge(); + + return this; + } +} diff --git a/src/cell/DumpColsCell.js b/src/cell/DumpColsCell.js index 560c728..ba1fede 100644 --- a/src/cell/DumpColsCell.js +++ b/src/cell/DumpColsCell.js @@ -18,7 +18,7 @@ export default class DumpColsCell extends BaseCell { cols.forEach((x) => { scope.setCurrentOutputValue(x); scope.applyStyles(); - scope.output_cell = Object.freeze({...scope.output_cell, c: scope.output_cell.c + 1}); + scope.outputCell = Object.freeze({ ...scope.outputCell, c: scope.outputCell.c + 1 }); }); scope.incrementCol(); diff --git a/src/cell/EndLoopCell.js b/src/cell/EndLoopCell.js index c0d7c1e..bc99f56 100644 --- a/src/cell/EndLoopCell.js +++ b/src/cell/EndLoopCell.js @@ -18,12 +18,12 @@ class EndLoopCell extends BaseCell { scope.vm[target] = Object.freeze({ ...scope.vm[target], - __end: scope.template_cell, + __end: scope.templateCell, __insetRows: true }); if (__start && !__iterated) { - scope.template_cell = __start; + scope.templateCell = __start; } else { scope.incrementRow(); } diff --git a/src/cell/FinishCell.js b/src/cell/FinishCell.js index 09e03f8..00fd080 100644 --- a/src/cell/FinishCell.js +++ b/src/cell/FinishCell.js @@ -6,20 +6,20 @@ class FinishCell extends BaseCell { super.apply(scope); scope.setCurrentOutputValue(null); - let wst = scope.template.worksheets[scope.template_cell.ws]; + let wst = scope.template.worksheets[scope.templateCell.ws]; if (FinishCell._getCondition(scope)) { //todo refactoring scope.iterateWorksheet - const wst_next = scope.template_cell.ws + 1; + const wst_next = scope.templateCell.ws + 1; wst = scope.template.worksheets[wst_next]; if (wst) { - scope.template_cell = Object.freeze({ - ...scope.template_cell, - ws: scope.template_cell.ws + 1, + scope.templateCell = Object.freeze({ + ...scope.templateCell, + ws: scope.templateCell.ws + 1, r: 1, c: 1 }); - scope.output_cell = Object.freeze({...scope.output_cell, ws: scope.output_cell.ws + 1, r: 1, c: 1}); + scope.outputCell = Object.freeze({ ...scope.outputCell, ws: scope.outputCell.ws + 1, r: 1, c: 1 }); scope.unfreezeOutput(); } @@ -27,10 +27,10 @@ class FinishCell extends BaseCell { scope.finish(); } } else {//todo refactoring scope.duplicateWorksheet - let wso = scope.output.addWorksheet(`Sheet ${scope.output_cell.ws + 1}`, wst); //todo if append , problems may happen + let wso = scope.output.addWorksheet(`Sheet ${scope.outputCell.ws + 1}`, wst); //todo if append , problems may happen - scope.template_cell = Object.freeze({...scope.template_cell, r: 1, c: 1}); - scope.output_cell = Object.freeze({...scope.output_cell, ws: scope.output_cell.ws + 1, r: 1, c: 1}); + scope.templateCell = Object.freeze({ ...scope.templateCell, r: 1, c: 1 }); + scope.outputCell = Object.freeze({ ...scope.outputCell, ws: scope.outputCell.ws + 1, r: 1, c: 1 }); // noinspection JSCheckFunctionSignatures - todo exceljs type mismatch diff --git a/src/cell/ForEachCell.js b/src/cell/ForEachCell.js index 544bc88..3baf630 100644 --- a/src/cell/ForEachCell.js +++ b/src/cell/ForEachCell.js @@ -30,9 +30,9 @@ class ForEachCell extends BaseCell { if (__index === 1) { super.apply(scope); } - - const __start = scope.vm[target] && scope.vm[target].__start || scope.template_cell; - const __startOutput = scope.vm[target] && scope.vm[target].__startOutput || scope.output_cell.r + 1; + + const __start = scope.vm[target] && scope.vm[target].__start || scope.templateCell; + const __startOutput = scope.vm[target] && scope.vm[target].__startOutput || scope.outputCell.r + 1; const __end = scope.vm[target] && scope.vm[target].__end; const __last = typeof __from.split('.').reduce((p, c) => p[c] || {}, scope.vm)[__index] === 'undefined'; let __endOutput = scope.vm[target] && scope.vm[target].__endOutput; @@ -57,17 +57,17 @@ class ForEachCell extends BaseCell { if (!scope.isFrozen()) { for (let i = __end.r; i > __start.r; i--) { // noinspection JSCheckFunctionSignatures - todo exceljs signature mismatch - scope.output.worksheets[scope.output_cell.ws].spliceRows( //todo refactoring - scope.output_cell.r + 1, + scope.output.worksheets[scope.outputCell.ws].spliceRows( //todo refactoring + scope.outputCell.r + 1, 0, - scope.template.worksheets[scope.template_cell.ws].getRow(i) + scope.template.worksheets[scope.templateCell.ws].getRow(i), ); } } } if (__iterated) { - __endOutput = __endOutput || scope.output_cell.r; + __endOutput = __endOutput || scope.outputCell.r; } scope.incrementRow(); diff --git a/src/cell/FormulaCell.js b/src/cell/FormulaCell.js index f5ae19c..91c1e55 100644 --- a/src/cell/FormulaCell.js +++ b/src/cell/FormulaCell.js @@ -10,7 +10,7 @@ class FormulaCell extends BaseCell { apply(scope) { super.apply(scope); - const shift = scope.output_cell.r - scope.template_cell.r; + const shift = scope.outputCell.r - scope.templateCell.r; const regex = /([a-zA-Z]+)([1-9][0-9]*)/g; const value = scope.getCurrentTemplateValue(); diff --git a/src/cell/NormalCell.js b/src/cell/NormalCell.js deleted file mode 100644 index 376a691..0000000 --- a/src/cell/NormalCell.js +++ /dev/null @@ -1,29 +0,0 @@ -import BaseCell from "./BaseCell"; -import {ValueType} from "exceljs"; - -class NormalCell extends BaseCell { - /** - * @inheritDoc - * @param {Scope} scope - * @returns {NormalCell} - */ - apply(scope) { - super.apply(scope); - - scope.incrementCol(); - - return this; - } - - /** - * @inheritDoc - * @param {Cell} cell - * @returns {boolean} - */ - static match(cell) { - return cell && cell.type === ValueType.String && typeof cell.value === 'string' && !['##', '#!'].includes(cell.value.substring(0, 2)); - } - -} - -export default NormalCell \ No newline at end of file diff --git a/src/cell/NormalCell.ts b/src/cell/NormalCell.ts new file mode 100644 index 0000000..9e37a2a --- /dev/null +++ b/src/cell/NormalCell.ts @@ -0,0 +1,33 @@ +import { Cell, ValueType } from 'exceljs'; + +import { BaseCell } from './BaseCell'; +import { Scope } from '../Scope'; + +export class NormalCell extends BaseCell { + /** + * @inheritDoc + * @param {Cell} cell + * @returns {boolean} + */ + public static match(cell: Cell) { + return ( + cell && + cell.type === ValueType.String && + typeof cell.value === 'string' && + !['##', '#!'].includes(cell.value.substring(0, 2)) + ); + } + + /** + * @inheritDoc + * @param {Scope} scope + * @returns {NormalCell} + */ + public apply(scope: Scope) { + super.apply(scope); + + scope.incrementCol(); + + return this; + } +} diff --git a/src/cell/SumCell.js b/src/cell/SumCell.js index d0b31ba..e158834 100644 --- a/src/cell/SumCell.js +++ b/src/cell/SumCell.js @@ -15,8 +15,8 @@ export default class SumCell extends BaseCell { const __endOutput = scope.vm[target] && scope.vm[target].__endOutput; if (__startOutput && __endOutput) { - const start = scope.output.worksheets[scope.output_cell.ws].getCell(__startOutput, scope.output_cell.c).address; //todo refactoring - const end = scope.output.worksheets[scope.output_cell.ws].getCell(__endOutput, scope.output_cell.c).address; //todo refactoring + const start = scope.output.worksheets[scope.outputCell.ws].getCell(__startOutput, scope.outputCell.c).address; //todo refactoring + const end = scope.output.worksheets[scope.outputCell.ws].getCell(__endOutput, scope.outputCell.c).address; //todo refactoring scope.setCurrentOutputValue({formula: `sum(${start}:${end})`}); } diff --git a/src/cell/VariableCell.js b/src/cell/VariableCell.js index 67d613f..a83a195 100644 --- a/src/cell/VariableCell.js +++ b/src/cell/VariableCell.js @@ -14,7 +14,7 @@ class VariableCell extends BaseCell { const value = path.reduce((p, c) => typeof p === 'object' ? p[c] : p, scope.vm); if (value === undefined) { //todo do it better (use logger or somethink like that) - console.log(`WARN: ${path} is undefined for output: ${scope.output_cell} when template is:${scope.template_cell}`); + console.log(`WARN: ${path} is undefined for output: ${scope.outputCell} when template is:${scope.templateCell}`); } scope.setCurrentOutputValue(value); scope.incrementCol(); diff --git a/src/cell/WsNameCell.js b/src/cell/WsNameCell.js index 69559c7..8f46d0f 100644 --- a/src/cell/WsNameCell.js +++ b/src/cell/WsNameCell.js @@ -12,7 +12,7 @@ export default class WsNameCell extends BaseCell { scope.setCurrentOutputValue(null); - scope.output.worksheets[scope.output_cell.ws].name = this._getName(scope); + scope.output.worksheets[scope.outputCell.ws].name = this._getName(scope); scope.incrementCol(); return this; @@ -28,7 +28,7 @@ export default class WsNameCell extends BaseCell { name = name.replace(/[\\\/*\[\]?]/g, '.'); if (scope.output.worksheets.find(x => x.name === name)) { - name += ` ${scope.output_cell.ws}`; + name += ` ${scope.outputCell.ws}`; } name = name.length > 31 ? name.substr(name.length - 31) : name; diff --git a/tests/Renderer.test.ts b/tests/Renderer.test.ts new file mode 100644 index 0000000..989c0dc --- /dev/null +++ b/tests/Renderer.test.ts @@ -0,0 +1,12 @@ +// import * as chai from 'chai' +// +// import Index from '../src/Renderer' +// +// describe('sample"', function () { +// +// it('sample test"', async function () { +// const index = new Index(); +// +// chai.expect(index.DoSomething()).eql("do nothing"); +// }); +// }); \ No newline at end of file diff --git a/tslint.json b/tslint.json index 71287e5..5c4c242 100644 --- a/tslint.json +++ b/tslint.json @@ -2,5 +2,9 @@ "extends": [ "tslint:recommended", "tslint-config-prettier" - ] + ], + "rules": { + "ordered-imports": false, + "object-literal-sort-keys": false + } } \ No newline at end of file From c11a6e28a23420f0d803a9b5ad265e423194a6f6 Mon Sep 17 00:00:00 2001 From: Pawel Siemienik Date: Sat, 1 Feb 2020 02:57:36 +0100 Subject: [PATCH 04/10] WIP: #2 next files migrated to ts from js --- .gitignore | 2 +- src/CellTemplateDebugPool.js | 17 ----------------- src/CellTemplateDebugPool.ts | 16 ++++++++++++++++ src/CellTemplatePool.ts | 8 ++++---- src/Renderer.ts | 2 +- src/cell/BaseCell.ts | 4 ++-- src/cell/{EndRowCell.js => EndRowCell.ts} | 16 ++++++---------- src/cell/{FinishCell.js => FinishCell.ts} | 16 ++++++++-------- src/cell/NormalCell.ts | 4 ++-- tests/index.test.ts | 12 ++++++++++++ 10 files changed, 52 insertions(+), 45 deletions(-) delete mode 100644 src/CellTemplateDebugPool.js create mode 100644 src/CellTemplateDebugPool.ts rename src/cell/{EndRowCell.js => EndRowCell.ts} (51%) rename src/cell/{FinishCell.js => FinishCell.ts} (85%) create mode 100644 tests/index.test.ts diff --git a/.gitignore b/.gitignore index ee8202e..543ecab 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,5 @@ /.idea/ -/src/example.js +/src/example.ts *.xlsx \ No newline at end of file diff --git a/src/CellTemplateDebugPool.js b/src/CellTemplateDebugPool.js deleted file mode 100644 index c119d89..0000000 --- a/src/CellTemplateDebugPool.js +++ /dev/null @@ -1,17 +0,0 @@ -import CellTemplatePool from "../xls-renderer/CellTemplatePool"; - -export default class CellTemplateDebugPool extends CellTemplatePool { - /** - * do normal match and log in console result. - * - * @param {Cell} cell - * @returns {BaseCell} - */ - match(cell) { - const result = super.match(cell); - - console.log(result, cell && cell.value); - - return result; - } -} diff --git a/src/CellTemplateDebugPool.ts b/src/CellTemplateDebugPool.ts new file mode 100644 index 0000000..7409633 --- /dev/null +++ b/src/CellTemplateDebugPool.ts @@ -0,0 +1,16 @@ +import { CellTemplatePool } from './CellTemplatePool'; +import { Cell } from 'exceljs'; +import { BaseCell } from './cell/BaseCell'; + +export class CellTemplateDebugPool extends CellTemplatePool { + /** + * do normal match and log in console result. + */ + match(cell: Cell): BaseCell { + const result = super.match(cell); + + console.log(result, cell && cell.value); + + return result; + } +} diff --git a/src/CellTemplatePool.ts b/src/CellTemplatePool.ts index 1f67846..11c0d55 100644 --- a/src/CellTemplatePool.ts +++ b/src/CellTemplatePool.ts @@ -3,11 +3,11 @@ import { Cell } from 'exceljs'; import { BaseCell, CellType } from './cell/BaseCell'; import { NormalCell } from './cell/NormalCell'; // import VariableCell from "./cell/VariableCell"; -// import FinishCell from "./cell/FinishCell"; +import { FinishCell } from './cell/FinishCell'; // import ForEachCell from "./cell/ForEachCell"; // import ContinueCell from "./cell/ContinueCell"; // import EndLoopCell from "./cell/EndLoopCell"; -// import EndRowCell from "./cell/EndRowCell"; +import { EndRowCell } from './cell/EndRowCell'; // import SumCell from "./cell/SumCell"; // import AverageCell from "./cell/AverageCell"; // import DeleteCell from "./cell/DeleteCell"; @@ -19,12 +19,12 @@ import { NormalCell } from './cell/NormalCell'; export class CellTemplatePool { protected cells: CellType[] = [ NormalCell, - // EndRowCell, + EndRowCell, // VariableCell, // FormulaCell, // HyperlinkCell, // ForEachCell, - // FinishCell, + FinishCell, // EndLoopCell, // ContinueCell, // DumpColsCell, diff --git a/src/Renderer.ts b/src/Renderer.ts index 587eebe..fa36b30 100644 --- a/src/Renderer.ts +++ b/src/Renderer.ts @@ -7,7 +7,7 @@ export class Renderer { constructor(private cellTemplatePool: CellTemplatePool = new CellTemplatePool()) { } - public async render(templateFactory: () => Workbook, vm: any): Promise { + public async render(templateFactory: () => Promise, vm: any): Promise { const template = await templateFactory(); const output = await templateFactory(); diff --git a/src/cell/BaseCell.ts b/src/cell/BaseCell.ts index 9277687..93d1c9b 100644 --- a/src/cell/BaseCell.ts +++ b/src/cell/BaseCell.ts @@ -8,7 +8,7 @@ export class BaseCell { /** * check if this commend can parse `value` */ - public static match(cell: Cell) { + public static match(cell: Cell): boolean { return false; } @@ -16,7 +16,7 @@ export class BaseCell { throw new TypeError(`Cannot construct ${BaseCell.name} instances directly. It's abstract.`); } - public apply(scope: Scope) { + public apply(scope: Scope): BaseCell { if (scope.outputCell.c > 16384) { scope.outputCell = Object.freeze({ ...scope.outputCell, c: 16384 }); } diff --git a/src/cell/EndRowCell.js b/src/cell/EndRowCell.ts similarity index 51% rename from src/cell/EndRowCell.js rename to src/cell/EndRowCell.ts index 8a75255..42bab0d 100644 --- a/src/cell/EndRowCell.js +++ b/src/cell/EndRowCell.ts @@ -1,13 +1,9 @@ -import BaseCell from "./BaseCell"; -import {ValueType} from "exceljs"; +import { BaseCell } from './BaseCell'; +import { Cell, ValueType } from 'exceljs'; +import { Scope } from '../Scope'; -export default class EndRowCell extends BaseCell { - /** - * @param {Scope} scope - * - * @returns {EndRowCell} - */ - apply(scope) { +export class EndRowCell extends BaseCell { + apply(scope: Scope): EndRowCell { super.apply(scope); scope.setCurrentOutputValue(null); @@ -16,7 +12,7 @@ export default class EndRowCell extends BaseCell { return this; } - static match(cell) { + static match(cell: Cell): boolean { return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value === '#! END_ROW'; } diff --git a/src/cell/FinishCell.js b/src/cell/FinishCell.ts similarity index 85% rename from src/cell/FinishCell.js rename to src/cell/FinishCell.ts index 00fd080..5c57bc3 100644 --- a/src/cell/FinishCell.js +++ b/src/cell/FinishCell.ts @@ -1,8 +1,9 @@ -import BaseCell from "./BaseCell"; -import {ValueType} from "exceljs"; +import { BaseCell } from './BaseCell'; +import { Cell, ValueType } from 'exceljs'; +import { Scope } from '../Scope'; -class FinishCell extends BaseCell { - apply(scope) { +export class FinishCell extends BaseCell { + apply(scope: Scope): FinishCell { super.apply(scope); scope.setCurrentOutputValue(null); @@ -41,7 +42,7 @@ class FinishCell extends BaseCell { return this; } - static match(cell) { + static match(cell: Cell): boolean { return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 9) === '#! FINISH'; } @@ -56,8 +57,8 @@ class FinishCell extends BaseCell { * @returns {boolean} * @protected */ - static _getCondition(scope) { - const args = scope.getCurrentTemplateValue().split(' '); + private static _getCondition(scope: Scope): boolean { + const args = scope.getCurrentTemplateValue()?.toString().split(' ') || []; if (args.length < 3) { return true; } @@ -69,4 +70,3 @@ class FinishCell extends BaseCell { } } -export default FinishCell \ No newline at end of file diff --git a/src/cell/NormalCell.ts b/src/cell/NormalCell.ts index 9e37a2a..3ed3ccd 100644 --- a/src/cell/NormalCell.ts +++ b/src/cell/NormalCell.ts @@ -9,7 +9,7 @@ export class NormalCell extends BaseCell { * @param {Cell} cell * @returns {boolean} */ - public static match(cell: Cell) { + public static match(cell: Cell): boolean { return ( cell && cell.type === ValueType.String && @@ -23,7 +23,7 @@ export class NormalCell extends BaseCell { * @param {Scope} scope * @returns {NormalCell} */ - public apply(scope: Scope) { + public apply(scope: Scope): NormalCell { super.apply(scope); scope.incrementCol(); diff --git a/tests/index.test.ts b/tests/index.test.ts new file mode 100644 index 0000000..447a17d --- /dev/null +++ b/tests/index.test.ts @@ -0,0 +1,12 @@ +// import * as chai from 'chai' +// +// import Index from '../src/Index' +// +// describe('sample"', function () { +// +// it('sample test"', async function () { +// const index = new Index(); +// +// chai.expect(index.DoSomething()).eql("do nothing"); +// }); +// }); \ No newline at end of file From 92b1613a90d262e8656f9adbfbd6e021f6c8c8fc Mon Sep 17 00:00:00 2001 From: Pawel Siemienik Date: Sat, 8 Feb 2020 23:04:10 +0100 Subject: [PATCH 05/10] WIP: #2 migrate to TS two another files: VariableCell and WsNameCell, Added ViewModel=any. Lint & format --- .github/workflows/nodejs.yml | 28 ++++++++++++ src/CellTemplateDebugPool.ts | 2 +- src/CellTemplatePool.ts | 8 ++-- src/ICellCoord.ts | 5 +++ src/Scope.ts | 10 ++--- src/ViewModel.ts | 1 + src/cell/EndRowCell.ts | 13 +++--- src/cell/FinishCell.ts | 86 +++++++++++++++++++----------------- src/cell/VariableCell.js | 36 --------------- src/cell/VariableCell.ts | 37 ++++++++++++++++ src/cell/WsNameCell.js | 65 --------------------------- src/cell/WsNameCell.ts | 54 ++++++++++++++++++++++ src/example.ts | 26 +++++++++++ 13 files changed, 211 insertions(+), 160 deletions(-) create mode 100644 .github/workflows/nodejs.yml create mode 100644 src/ICellCoord.ts create mode 100644 src/ViewModel.ts delete mode 100644 src/cell/VariableCell.js create mode 100644 src/cell/VariableCell.ts delete mode 100644 src/cell/WsNameCell.js create mode 100644 src/cell/WsNameCell.ts create mode 100644 src/example.ts diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 0000000..44f7744 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,28 @@ +name: lint-build-test + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [8.x, 10.x, 12.x] + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: npm install, lint, build, and test + run: | + npm install + npm list + npm run lint + npm run build + npm run test + env: + CI: true diff --git a/src/CellTemplateDebugPool.ts b/src/CellTemplateDebugPool.ts index 7409633..5cee4f6 100644 --- a/src/CellTemplateDebugPool.ts +++ b/src/CellTemplateDebugPool.ts @@ -6,7 +6,7 @@ export class CellTemplateDebugPool extends CellTemplatePool { /** * do normal match and log in console result. */ - match(cell: Cell): BaseCell { + public match(cell: Cell): BaseCell { const result = super.match(cell); console.log(result, cell && cell.value); diff --git a/src/CellTemplatePool.ts b/src/CellTemplatePool.ts index 11c0d55..6350fe3 100644 --- a/src/CellTemplatePool.ts +++ b/src/CellTemplatePool.ts @@ -2,7 +2,7 @@ import { Cell } from 'exceljs'; import { BaseCell, CellType } from './cell/BaseCell'; import { NormalCell } from './cell/NormalCell'; -// import VariableCell from "./cell/VariableCell"; +import { VariableCell } from './cell/VariableCell'; import { FinishCell } from './cell/FinishCell'; // import ForEachCell from "./cell/ForEachCell"; // import ContinueCell from "./cell/ContinueCell"; @@ -12,7 +12,7 @@ import { EndRowCell } from './cell/EndRowCell'; // import AverageCell from "./cell/AverageCell"; // import DeleteCell from "./cell/DeleteCell"; // import DumpColsCell from "./cell/DumpColsCell"; -// import WsNameCell from "./cell/WsNameCell"; +import { WsNameCell } from './cell/WsNameCell'; // import HyperlinkCell from "./cell/HyperlinkCell"; // import FormulaCell from "./cell/FormulaCell"; @@ -20,7 +20,7 @@ export class CellTemplatePool { protected cells: CellType[] = [ NormalCell, EndRowCell, - // VariableCell, + VariableCell, // FormulaCell, // HyperlinkCell, // ForEachCell, @@ -30,7 +30,7 @@ export class CellTemplatePool { // DumpColsCell, // SumCell, // AverageCell, - // WsNameCell, + WsNameCell, // DeleteCell, ]; diff --git a/src/ICellCoord.ts b/src/ICellCoord.ts new file mode 100644 index 0000000..0a1eb07 --- /dev/null +++ b/src/ICellCoord.ts @@ -0,0 +1,5 @@ +export interface ICellCoord { + r: number; + c: number; + ws: number; +} diff --git a/src/Scope.ts b/src/Scope.ts index 7322fdf..e0f055b 100644 --- a/src/Scope.ts +++ b/src/Scope.ts @@ -1,10 +1,6 @@ import { Address, Cell, CellValue, Workbook } from 'exceljs'; - -export interface ICellCoord { - r: number; - c: number; - ws: number; -} +import { ViewModel } from './ViewModel'; +import { ICellCoord } from './ICellCoord'; export class Scope { public outputCell: ICellCoord = Object.freeze({ r: 1, c: 1, ws: 0 }); @@ -17,7 +13,7 @@ export class Scope { private finished: boolean = false; - constructor(public template: Workbook, public output: Workbook, public vm: any) { + constructor(public template: Workbook, public output: Workbook, public vm: ViewModel) { } public getCurrentTemplateValue(): CellValue { diff --git a/src/ViewModel.ts b/src/ViewModel.ts new file mode 100644 index 0000000..e5671f0 --- /dev/null +++ b/src/ViewModel.ts @@ -0,0 +1 @@ +export type ViewModel = any; diff --git a/src/cell/EndRowCell.ts b/src/cell/EndRowCell.ts index 42bab0d..8c2040e 100644 --- a/src/cell/EndRowCell.ts +++ b/src/cell/EndRowCell.ts @@ -3,7 +3,11 @@ import { Cell, ValueType } from 'exceljs'; import { Scope } from '../Scope'; export class EndRowCell extends BaseCell { - apply(scope: Scope): EndRowCell { + public static match(cell: Cell): boolean { + return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value === '#! END_ROW'; + } + + public apply(scope: Scope): EndRowCell { super.apply(scope); scope.setCurrentOutputValue(null); @@ -11,9 +15,4 @@ export class EndRowCell extends BaseCell { return this; } - - static match(cell: Cell): boolean { - return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value === '#! END_ROW'; - } - -} \ No newline at end of file +} diff --git a/src/cell/FinishCell.ts b/src/cell/FinishCell.ts index 5c57bc3..5422046 100644 --- a/src/cell/FinishCell.ts +++ b/src/cell/FinishCell.ts @@ -3,70 +3,76 @@ import { Cell, ValueType } from 'exceljs'; import { Scope } from '../Scope'; export class FinishCell extends BaseCell { - apply(scope: Scope): FinishCell { + public static match(cell: Cell): boolean { + return ( + cell && + cell.type === ValueType.String && + typeof cell.value === 'string' && + cell.value.substring(0, 9) === '#! FINISH' + ); + } + + /** + * Rendering should finish when: + * * condition params isn't set + * * condition's path follow to undefined + * * condition is true + * In other way, the same template sheet should render next output sheet - as long as condition is false + * + * @param {Scope} scope + * @returns {boolean} + * @protected + */ + private static _getCondition(scope: Scope): boolean { + const args = + scope + .getCurrentTemplateValue() + ?.toString() + .split(' ') || []; + if (args.length < 3) { + return true; + } + + return !!args[2] + .split('.') + .reduce((p, c) => typeof p === 'undefined' || typeof p[c] === 'undefined' || p[c], scope.vm); + } + + public apply(scope: Scope): FinishCell { super.apply(scope); scope.setCurrentOutputValue(null); let wst = scope.template.worksheets[scope.templateCell.ws]; - if (FinishCell._getCondition(scope)) { //todo refactoring scope.iterateWorksheet + if (FinishCell._getCondition(scope)) { + // todo refactoring scope.iterateWorksheet - const wst_next = scope.templateCell.ws + 1; - wst = scope.template.worksheets[wst_next]; + const wstNext = scope.templateCell.ws + 1; + wst = scope.template.worksheets[wstNext]; if (wst) { scope.templateCell = Object.freeze({ ...scope.templateCell, ws: scope.templateCell.ws + 1, r: 1, - c: 1 + c: 1, }); scope.outputCell = Object.freeze({ ...scope.outputCell, ws: scope.outputCell.ws + 1, r: 1, c: 1 }); scope.unfreezeOutput(); - } - else { + } else { scope.finish(); } - } else {//todo refactoring scope.duplicateWorksheet - let wso = scope.output.addWorksheet(`Sheet ${scope.outputCell.ws + 1}`, wst); //todo if append , problems may happen + } else { + // todo refactoring scope.duplicateWorksheet + const wso = scope.output.addWorksheet(`Sheet ${scope.outputCell.ws + 1}`, wst); // todo if append , problems may happen scope.templateCell = Object.freeze({ ...scope.templateCell, r: 1, c: 1 }); scope.outputCell = Object.freeze({ ...scope.outputCell, ws: scope.outputCell.ws + 1, r: 1, c: 1 }); - // noinspection JSCheckFunctionSignatures - todo exceljs type mismatch - wst.getImages().forEach((i) => wso.addImage(+i.imageId, i.range)); + wst.getImages().forEach(i => wso.addImage(+i.imageId, i.range)); } - return this; } - - static match(cell: Cell): boolean { - return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 9) === '#! FINISH'; - } - - /** - * Rendering should finish when: - * * condition params isn't set - * * condition's path follow to undefined - * * condition is true - * In other way, the same template sheet should render next output sheet - as long as condition is false - * - * @param {Scope} scope - * @returns {boolean} - * @protected - */ - private static _getCondition(scope: Scope): boolean { - const args = scope.getCurrentTemplateValue()?.toString().split(' ') || []; - if (args.length < 3) { - return true; - } - - return !!args[2].split('.').reduce( - (p, c) => typeof p === 'undefined' || typeof p[c] === 'undefined' || p[c], - scope.vm - ); - } } - diff --git a/src/cell/VariableCell.js b/src/cell/VariableCell.js deleted file mode 100644 index a83a195..0000000 --- a/src/cell/VariableCell.js +++ /dev/null @@ -1,36 +0,0 @@ -import BaseCell from "./BaseCell"; -import {ValueType} from "exceljs"; - -class VariableCell extends BaseCell { - /** - * @inheritDoc - * @param {Scope} scope - * @returns {VariableCell} - */ - apply(scope) { - super.apply(scope); - - const path = scope.getCurrentTemplateValue().substring(3).split('.'); - - const value = path.reduce((p, c) => typeof p === 'object' ? p[c] : p, scope.vm); - if (value === undefined) { //todo do it better (use logger or somethink like that) - console.log(`WARN: ${path} is undefined for output: ${scope.outputCell} when template is:${scope.templateCell}`); - } - scope.setCurrentOutputValue(value); - scope.incrementCol(); - - return this; - } - - /** - * @inheritDoc - * @param {Cell} cell - * @returns {boolean} - */ - static match(cell) { - return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 2) === '##'; - } - -} - -export default VariableCell \ No newline at end of file diff --git a/src/cell/VariableCell.ts b/src/cell/VariableCell.ts new file mode 100644 index 0000000..dff3f72 --- /dev/null +++ b/src/cell/VariableCell.ts @@ -0,0 +1,37 @@ +import { BaseCell } from './BaseCell'; +import { Cell, ValueType } from 'exceljs'; +import { Scope } from '../Scope'; + +export class VariableCell extends BaseCell { + public static match(cell: Cell): boolean { + return ( + cell && + cell.type === ValueType.String && + typeof cell.value === 'string' && + cell.value.substring(0, 2) === '##' + ); + } + + public apply(scope: Scope) { + super.apply(scope); + + const path = + scope + .getCurrentTemplateValue() + ?.toString() + .substring(3) + .split('.') || []; + + const value = path.reduce((p, c) => (typeof p === 'object' ? p[c] : p), scope.vm); + if (value === undefined) { + // todo do it better (use logger or somethink like that) + console.warn( + `WARN: ${path} is undefined for output: ${scope.outputCell} when template is:${scope.templateCell}`, + ); + } + scope.setCurrentOutputValue(value); + scope.incrementCol(); + + return this; + } +} diff --git a/src/cell/WsNameCell.js b/src/cell/WsNameCell.js deleted file mode 100644 index 8f46d0f..0000000 --- a/src/cell/WsNameCell.js +++ /dev/null @@ -1,65 +0,0 @@ -import BaseCell from "./BaseCell"; -import {ValueType} from "exceljs"; - -export default class WsNameCell extends BaseCell { - /** - * @param {Scope} scope - * - * @returns {WsNameCell} - */ - apply(scope) { - super.apply(scope); - - scope.setCurrentOutputValue(null); - - scope.output.worksheets[scope.outputCell.ws].name = this._getName(scope); - scope.incrementCol(); - - return this; - } - - /** - * @param {Scope} scope - * @returns {string} - * @protected - */ - _getName(scope) { - let name = WsNameCell._getTargetValue(scope) || WsNameCell._getTarget(scope); - name = name.replace(/[\\\/*\[\]?]/g, '.'); - - if (scope.output.worksheets.find(x => x.name === name)) { - name += ` ${scope.outputCell.ws}`; - } - - name = name.length > 31 ? name.substr(name.length - 31) : name; - - return name; - } - - /** - * @param {Scope} scope - * @returns {string} - * @protected - */ - static _getTargetValue(scope) { - return WsNameCell._getTarget(scope).split('.').reduce((p, c) => p[c] || "", scope.vm); - } - - /** - * @param {Scope} scope - * @returns {string} - * @protected - */ - static _getTarget(scope) { - return scope.getCurrentTemplateValue().split(' ')[2]; - } - - /** - * @param {Cell} cell - * @return {boolean} - */ - static match(cell) { - return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 10) === '#! WS_NAME'; - } - -} \ No newline at end of file diff --git a/src/cell/WsNameCell.ts b/src/cell/WsNameCell.ts new file mode 100644 index 0000000..98ef85c --- /dev/null +++ b/src/cell/WsNameCell.ts @@ -0,0 +1,54 @@ +import { BaseCell } from './BaseCell'; +import { Cell, ValueType } from 'exceljs'; +import { Scope } from '../Scope'; +import { ViewModel } from '../ViewModel'; + +export class WsNameCell extends BaseCell { + public static match(cell: Cell): boolean { + return ( + cell && + cell.type === ValueType.String && + typeof cell.value === 'string' && + cell.value.substring(0, 10) === '#! WS_NAME' + ); + } + + protected static _getName(scope: Scope): string { + let name = WsNameCell._getTargetValue(scope) || WsNameCell._getTarget(scope); + name = name.replace(/[\\\/*\[\]?]/g, '.'); + + if (scope.output.worksheets.find(x => x.name === name)) { + name += ` ${scope.outputCell.ws}`; + } + + name = name.length > 31 ? name.substr(name.length - 31) : name; + + return name; + } + + protected static _getTargetValue(scope: Scope) { + return WsNameCell._getTarget(scope) + .split('.') + .reduce((p: ViewModel, c: string) => p[c] || '', scope.vm); + } + + protected static _getTarget(scope: Scope): string { + return ( + scope + .getCurrentTemplateValue() + ?.toString() + .split(' ')[2] || '' + ); + } + + public apply(scope: Scope): WsNameCell { + super.apply(scope); + + scope.setCurrentOutputValue(null); + + scope.output.worksheets[scope.outputCell.ws].name = WsNameCell._getName(scope); + scope.incrementCol(); + + return this; + } +} diff --git a/src/example.ts b/src/example.ts new file mode 100644 index 0000000..48ccadb --- /dev/null +++ b/src/example.ts @@ -0,0 +1,26 @@ +import { Renderer } from './Renderer'; +import { CellTemplateDebugPool } from './CellTemplateDebugPool'; +import { CellTemplatePool } from './CellTemplatePool'; +import { Workbook } from 'exceljs'; + +//* +const debug = true; +/*/ +const debug = false; +//*/ + +let renderer; +if (debug) { + renderer = new Renderer(new CellTemplateDebugPool()); +} else { + renderer = new Renderer(new CellTemplatePool()); +} + +(async () => { + const result = await renderer.render(async () => { + const template = new Workbook(); + return await template.xlsx.readFile('./my-awesome-raport-template.xlsx'); + }, {}); + + await result.xlsx.writeFile('./my-awesome-raport.xlsx'); +})(); From f1f5bb492485beebd3f9b2890070515e6534e175 Mon Sep 17 00:00:00 2001 From: Pawel Siemienik Date: Sat, 15 Feb 2020 11:13:32 +0100 Subject: [PATCH 06/10] WIP: #2 three classes migrated to typescript --- src/CellTemplatePool.ts | 12 ++--- src/cell/DeleteCell.js | 22 --------- src/cell/DeleteCell.ts | 25 ++++++++++ src/cell/{FormulaCell.js => FormulaCell.ts} | 37 +++++++-------- src/cell/HyperlinkCell.js | 52 --------------------- src/cell/HyperlinkCell.ts | 34 ++++++++++++++ 6 files changed, 83 insertions(+), 99 deletions(-) delete mode 100644 src/cell/DeleteCell.js create mode 100644 src/cell/DeleteCell.ts rename src/cell/{FormulaCell.js => FormulaCell.ts} (67%) delete mode 100644 src/cell/HyperlinkCell.js create mode 100644 src/cell/HyperlinkCell.ts diff --git a/src/CellTemplatePool.ts b/src/CellTemplatePool.ts index 6350fe3..7cfdc27 100644 --- a/src/CellTemplatePool.ts +++ b/src/CellTemplatePool.ts @@ -10,19 +10,19 @@ import { FinishCell } from './cell/FinishCell'; import { EndRowCell } from './cell/EndRowCell'; // import SumCell from "./cell/SumCell"; // import AverageCell from "./cell/AverageCell"; -// import DeleteCell from "./cell/DeleteCell"; +import { DeleteCell } from './cell/DeleteCell'; // import DumpColsCell from "./cell/DumpColsCell"; import { WsNameCell } from './cell/WsNameCell'; -// import HyperlinkCell from "./cell/HyperlinkCell"; -// import FormulaCell from "./cell/FormulaCell"; +import { HyperlinkCell } from './cell/HyperlinkCell'; +import { FormulaCell } from './cell/FormulaCell'; export class CellTemplatePool { protected cells: CellType[] = [ NormalCell, EndRowCell, VariableCell, - // FormulaCell, - // HyperlinkCell, + FormulaCell, + HyperlinkCell, // ForEachCell, FinishCell, // EndLoopCell, @@ -31,7 +31,7 @@ export class CellTemplatePool { // SumCell, // AverageCell, WsNameCell, - // DeleteCell, + DeleteCell, ]; protected instances: { [key: string]: BaseCell } = {}; diff --git a/src/cell/DeleteCell.js b/src/cell/DeleteCell.js deleted file mode 100644 index 9251735..0000000 --- a/src/cell/DeleteCell.js +++ /dev/null @@ -1,22 +0,0 @@ -import BaseCell from "./BaseCell"; -import {ValueType} from "exceljs"; - -export default class DeleteCell extends BaseCell { - apply(scope) { - super.apply(scope); - - const target = scope.getCurrentTemplateValue().split(' ')[2]; - - scope.vm[target] = undefined; - - scope.setCurrentOutputValue(null); - scope.incrementCol(); - - return this; - } - - static match(cell) { - return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 9) === '#! DELETE'; - } - -} \ No newline at end of file diff --git a/src/cell/DeleteCell.ts b/src/cell/DeleteCell.ts new file mode 100644 index 0000000..cdb228d --- /dev/null +++ b/src/cell/DeleteCell.ts @@ -0,0 +1,25 @@ +import { BaseCell } from './BaseCell'; +import { Cell, ValueType } from 'exceljs'; +import { Scope } from '../Scope'; + +export class DeleteCell extends BaseCell { + public static match(cell: Cell): boolean { + return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 9) === '#! DELETE'; + } + + public apply(scope: Scope): DeleteCell { + super.apply(scope); + + const target = scope.getCurrentTemplateValue()?.toString().split(' ')[2]; //todo make some function for scope.getCurrentTemplateValue()?.toString().split(' ') ; + + if (target == undefined) return this; //it's ok here + + scope.vm[target] = undefined; + + scope.setCurrentOutputValue(null); + scope.incrementCol(); + + return this; + } + +} \ No newline at end of file diff --git a/src/cell/FormulaCell.js b/src/cell/FormulaCell.ts similarity index 67% rename from src/cell/FormulaCell.js rename to src/cell/FormulaCell.ts index 91c1e55..e7026a2 100644 --- a/src/cell/FormulaCell.js +++ b/src/cell/FormulaCell.ts @@ -1,19 +1,29 @@ -import BaseCell from "./BaseCell"; -import {ValueType} from "exceljs"; +import { BaseCell } from './BaseCell'; +import { Cell, CellFormulaValue, ValueType } from 'exceljs'; +import { Scope } from '../Scope'; + +export class FormulaCell extends BaseCell { + /** + * @inheritDoc + * @param {Cell} cell + * @returns {boolean} + */ + public static match(cell: Cell): boolean { + return cell && cell.type === ValueType.Formula; + } -class FormulaCell extends BaseCell { /** * @inheritDoc * @param {Scope} scope * @returns {FormulaCell} */ - apply(scope) { + public apply(scope: Scope): FormulaCell { super.apply(scope); const shift = scope.outputCell.r - scope.templateCell.r; const regex = /([a-zA-Z]+)([1-9][0-9]*)/g; - const value = scope.getCurrentTemplateValue(); + const value = scope.getCurrentTemplateValue() as CellFormulaValue; let formula = value.formula; //todo extract method match addresses @@ -25,26 +35,15 @@ class FormulaCell extends BaseCell { addresses.reverse(); //todo extract method getShiftedFormula - let formulaChars = [...formula]; + let formulaChars = Array.from(formula); addresses.forEach(a => formulaChars.splice(a.index, a.len, `${a.col}${a.row + shift}`)); formula = formulaChars.join(''); - scope.setCurrentOutputValue({formula}); + scope.setCurrentOutputValue({ formula } as CellFormulaValue); scope.incrementCol(); return this; } - /** - * @inheritDoc - * @param {Cell} cell - * @returns {boolean} - */ - static match(cell) { - return cell && cell.type === ValueType.Formula; - } - -} - -export default FormulaCell \ No newline at end of file +} \ No newline at end of file diff --git a/src/cell/HyperlinkCell.js b/src/cell/HyperlinkCell.js deleted file mode 100644 index ad0c351..0000000 --- a/src/cell/HyperlinkCell.js +++ /dev/null @@ -1,52 +0,0 @@ -import BaseCell from "./BaseCell"; -import Scope from "../Scope"; -import {ValueType} from "exceljs"; - -export default class HyperlinkCell extends BaseCell { - /** - * @param {Scope} scope - * @returns {HyperlinkCell} - */ - apply(scope) { - super.apply(scope); - - scope.setCurrentOutputValue(null); - - const url = HyperlinkCell._getUrlParam(scope).split('.').reduce((p, c) => p[c] || {}, scope.vm); - if (typeof url === 'string') { - const label = HyperlinkCell._getLabelParam(scope).split('.').reduce((p, c) => p[c] || {}, scope.vm) || url; - console.log(label); - scope.setCurrentOutputValue({text: label, hyperlink: url}); - } - - scope.incrementCol(); - - return this; - } - - /** - * @param {Scope} scope - * @returns {string} - * @protected - */ - static _getLabelParam(scope) { - return scope.getCurrentTemplateValue().split(' ')[2]; - } - - /** - * @param {Scope} scope - * @returns {string} - * @protected - */ - static _getUrlParam(scope) { - return scope.getCurrentTemplateValue().split(' ')[3]; - } - - /** - * @param {Cell} cell - * @returns {boolean} - */ - static match(cell) { - return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 12) === '#! HYPERLINK'; - } -} \ No newline at end of file diff --git a/src/cell/HyperlinkCell.ts b/src/cell/HyperlinkCell.ts new file mode 100644 index 0000000..b14d6d2 --- /dev/null +++ b/src/cell/HyperlinkCell.ts @@ -0,0 +1,34 @@ +import { BaseCell } from './BaseCell'; +import { Scope } from '../Scope'; +import { Cell, ValueType } from 'exceljs'; + +export class HyperlinkCell extends BaseCell { + public static match(cell: Cell): boolean { + return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 12) === '#! HYPERLINK'; + } + + protected static getLabelParam(scope: Scope): string { + return scope.getCurrentTemplateValue()?.toString().split(' ')[2] || ''; + } + + protected static getUrlParam(scope: Scope): string { + return scope.getCurrentTemplateValue()?.toString().split(' ')[3] || ''; + } + + public apply(scope: Scope): HyperlinkCell { + super.apply(scope); + + scope.setCurrentOutputValue(null); + + const url = HyperlinkCell.getUrlParam(scope).split('.').reduce((p, c) => p[c] || {}, scope.vm); + if (typeof url === 'string') { + const label = HyperlinkCell.getLabelParam(scope).split('.').reduce((p, c) => p[c] || {}, scope.vm) || url; + console.log(label); + scope.setCurrentOutputValue({ text: label, hyperlink: url }); + } + + scope.incrementCol(); + + return this; + } +} \ No newline at end of file From 5c601d33f723790c5147b98c6de589faf2f937a9 Mon Sep 17 00:00:00 2001 From: Pawel Siemienik Date: Sat, 15 Feb 2020 20:47:58 +0100 Subject: [PATCH 07/10] Done: #2 all classes has been migrated to typescript --- src/CellTemplatePool.ts | 24 +++---- src/cell/{AverageCell.js => AverageCell.ts} | 35 ++++------ src/cell/ContinueCell.js | 28 -------- src/cell/ContinueCell.ts | 16 +++++ src/cell/DumpColsCell.js | 38 ----------- src/cell/DumpColsCell.ts | 29 +++++++++ src/cell/EndLoopCell.js | 45 ------------- src/cell/EndLoopCell.ts | 42 ++++++++++++ src/cell/{ForEachCell.js => ForEachCell.ts} | 71 ++++++++------------- src/cell/{SumCell.js => SumCell.ts} | 45 +++++-------- 10 files changed, 151 insertions(+), 222 deletions(-) rename src/cell/{AverageCell.js => AverageCell.ts} (52%) delete mode 100644 src/cell/ContinueCell.js create mode 100644 src/cell/ContinueCell.ts delete mode 100644 src/cell/DumpColsCell.js create mode 100644 src/cell/DumpColsCell.ts delete mode 100644 src/cell/EndLoopCell.js create mode 100644 src/cell/EndLoopCell.ts rename src/cell/{ForEachCell.js => ForEachCell.ts} (68%) rename src/cell/{SumCell.js => SumCell.ts} (53%) diff --git a/src/CellTemplatePool.ts b/src/CellTemplatePool.ts index 7cfdc27..0ec3bf8 100644 --- a/src/CellTemplatePool.ts +++ b/src/CellTemplatePool.ts @@ -4,14 +4,14 @@ import { BaseCell, CellType } from './cell/BaseCell'; import { NormalCell } from './cell/NormalCell'; import { VariableCell } from './cell/VariableCell'; import { FinishCell } from './cell/FinishCell'; -// import ForEachCell from "./cell/ForEachCell"; -// import ContinueCell from "./cell/ContinueCell"; -// import EndLoopCell from "./cell/EndLoopCell"; +import { ForEachCell } from './cell/ForEachCell'; +import { ContinueCell } from './cell/ContinueCell'; +import { EndLoopCell } from './cell/EndLoopCell'; import { EndRowCell } from './cell/EndRowCell'; -// import SumCell from "./cell/SumCell"; -// import AverageCell from "./cell/AverageCell"; +import { SumCell } from './cell/SumCell'; +import { AverageCell } from './cell/AverageCell'; import { DeleteCell } from './cell/DeleteCell'; -// import DumpColsCell from "./cell/DumpColsCell"; +import { DumpColsCell } from './cell/DumpColsCell'; import { WsNameCell } from './cell/WsNameCell'; import { HyperlinkCell } from './cell/HyperlinkCell'; import { FormulaCell } from './cell/FormulaCell'; @@ -23,13 +23,13 @@ export class CellTemplatePool { VariableCell, FormulaCell, HyperlinkCell, - // ForEachCell, + ForEachCell, FinishCell, - // EndLoopCell, - // ContinueCell, - // DumpColsCell, - // SumCell, - // AverageCell, + EndLoopCell, + ContinueCell, + DumpColsCell, + SumCell, + AverageCell, WsNameCell, DeleteCell, ]; diff --git a/src/cell/AverageCell.js b/src/cell/AverageCell.ts similarity index 52% rename from src/cell/AverageCell.js rename to src/cell/AverageCell.ts index 7476b8c..3512512 100644 --- a/src/cell/AverageCell.js +++ b/src/cell/AverageCell.ts @@ -1,16 +1,12 @@ -import BaseCell from "./BaseCell"; -import Scope from "../Scope"; -import {ValueType} from "exceljs"; - -export default class AverageCell extends BaseCell { - /** - * @param {Scope} scope - * @returns {AverageCell} - */ - apply(scope) { +import { BaseCell } from './BaseCell'; +import { Scope } from '../Scope'; +import { Cell, CellFormulaValue, ValueType } from 'exceljs'; + +export class AverageCell extends BaseCell { + public apply(scope: Scope): AverageCell { super.apply(scope); - const target = AverageCell._getTargetParam(scope); + const target = AverageCell.getTargetParam(scope); const __startOutput = scope.vm[target] && scope.vm[target].__startOutput; const __endOutput = scope.vm[target] && scope.vm[target].__endOutput; @@ -18,7 +14,7 @@ export default class AverageCell extends BaseCell { const start = scope.output.worksheets[scope.outputCell.ws].getCell(__startOutput, scope.outputCell.c).address; //todo refactoring const end = scope.output.worksheets[scope.outputCell.ws].getCell(__endOutput, scope.outputCell.c).address; //todo refactoring - scope.setCurrentOutputValue({formula: `average(${start}:${end})`}); + scope.setCurrentOutputValue({ formula: `average(${start}:${end})` } as CellFormulaValue); } scope.incrementCol(); @@ -26,20 +22,11 @@ export default class AverageCell extends BaseCell { return this; } - /** - * @param {Scope} scope - * @returns {string} - * @protected - */ - static _getTargetParam(scope) { - return scope.getCurrentTemplateValue().split(' ')[2]; + protected static getTargetParam(scope: Scope): string { + return scope.getCurrentTemplateValue()?.toString().split(' ')[2] || ''; } - /** - * @param {Cell} cell - * @returns {boolean} - */ - static match(cell) { + public static match(cell: Cell): boolean { return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 10) === '#! AVERAGE'; } } \ No newline at end of file diff --git a/src/cell/ContinueCell.js b/src/cell/ContinueCell.js deleted file mode 100644 index 5f90ead..0000000 --- a/src/cell/ContinueCell.js +++ /dev/null @@ -1,28 +0,0 @@ -import ForEachCell from "./ForEachCell"; -import {ValueType} from "exceljs"; - -class ContinueCell extends ForEachCell { - /** - * @inheritDoc - * @param {Scope} scope - * @returns {string} - * @protected - */ - _getFromParam(scope) { - const target = ForEachCell._getTargetParam(scope); - - return scope.vm[target] && scope.vm[target].__from; - } - - /** - * @inheritDoc - * @param {Cell} cell - * @returns {boolean} - */ - static match(cell) { - return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 11) === '#! CONTINUE'; - } - -} - -export default ContinueCell \ No newline at end of file diff --git a/src/cell/ContinueCell.ts b/src/cell/ContinueCell.ts new file mode 100644 index 0000000..d614e11 --- /dev/null +++ b/src/cell/ContinueCell.ts @@ -0,0 +1,16 @@ +import { ForEachCell } from './ForEachCell'; +import { Cell, ValueType } from 'exceljs'; +import { Scope } from '../Scope'; + +export class ContinueCell extends ForEachCell { + public static match(cell: Cell): boolean { + return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 11) === '#! CONTINUE'; + } + + public getSourceParam(scope: Scope): string { + const target = ForEachCell.getTargetParam(scope); + + return scope.vm[target] && scope.vm[target].__from; + } + +} diff --git a/src/cell/DumpColsCell.js b/src/cell/DumpColsCell.js deleted file mode 100644 index ba1fede..0000000 --- a/src/cell/DumpColsCell.js +++ /dev/null @@ -1,38 +0,0 @@ -import BaseCell from "./BaseCell"; -import {ValueType} from "exceljs"; - -export default class DumpColsCell extends BaseCell { - /** - * @inheritDoc - * @param {Scope} scope - * @returns {DumpColsCell} - */ - apply(scope) { - super.apply(scope); - - const path = scope.getCurrentTemplateValue().substring(13).split('.'); - const cols = path.reduce((p, c) => p[c] || [], scope.vm); - - scope.setCurrentOutputValue(null); - - cols.forEach((x) => { - scope.setCurrentOutputValue(x); - scope.applyStyles(); - scope.outputCell = Object.freeze({ ...scope.outputCell, c: scope.outputCell.c + 1 }); - }); - - scope.incrementCol(); - - return this; - } - - /** - * @inheritDoc - * @param {Cell} cell - * @returns {boolean} - */ - static match(cell) { - return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 12) === '#! DUMP_COLS'; - } - -} diff --git a/src/cell/DumpColsCell.ts b/src/cell/DumpColsCell.ts new file mode 100644 index 0000000..a1a8167 --- /dev/null +++ b/src/cell/DumpColsCell.ts @@ -0,0 +1,29 @@ +import { BaseCell } from './BaseCell'; +import { Cell, ValueType } from 'exceljs'; +import { Scope } from '../Scope'; + +export class DumpColsCell extends BaseCell { + static match(cell: Cell): boolean { + return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 12) === '#! DUMP_COLS'; + } + + public apply(scope: Scope): DumpColsCell { + super.apply(scope); + + const path = scope.getCurrentTemplateValue()?.toString().substring(13).split('.') || ''; + const cols = Array.from(path).reduce((p, c) => p[c] || [], scope.vm); + + scope.setCurrentOutputValue(null); + + cols.forEach((x: any) => { + scope.setCurrentOutputValue(x); + scope.applyStyles(); + scope.outputCell = Object.freeze({ ...scope.outputCell, c: scope.outputCell.c + 1 }); + }); + + scope.incrementCol(); + + return this; + } + +} diff --git a/src/cell/EndLoopCell.js b/src/cell/EndLoopCell.js deleted file mode 100644 index bc99f56..0000000 --- a/src/cell/EndLoopCell.js +++ /dev/null @@ -1,45 +0,0 @@ -import BaseCell from "./BaseCell"; -import {ValueType} from "exceljs"; - -class EndLoopCell extends BaseCell { - /** - * @inheritDoc - * @param {Scope} scope - * @returns {EndLoopCell} - */ - apply(scope) { - super.apply(scope); - - const target = scope.getCurrentTemplateValue().split(' ')[2]; - const __start = scope.vm[target] && scope.vm[target].__start; - const __iterated = scope.vm[target] && scope.vm[target].__iterated; - - scope.unfreezeOutput(); - - scope.vm[target] = Object.freeze({ - ...scope.vm[target], - __end: scope.templateCell, - __insetRows: true - }); - - if (__start && !__iterated) { - scope.templateCell = __start; - } else { - scope.incrementRow(); - } - - return this; - } - - /** - * @inheritDoc - * @param {Cell} cell - * @returns {boolean} - */ - static match(cell) { - return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 11) === '#! END_LOOP'; - } - -} - -export default EndLoopCell \ No newline at end of file diff --git a/src/cell/EndLoopCell.ts b/src/cell/EndLoopCell.ts new file mode 100644 index 0000000..0088a68 --- /dev/null +++ b/src/cell/EndLoopCell.ts @@ -0,0 +1,42 @@ +import { BaseCell } from './BaseCell'; +import { Cell, ValueType } from 'exceljs'; +import { Scope } from '../Scope'; + +export class EndLoopCell extends BaseCell { + public static match(cell: Cell): boolean { + return ( + cell && + cell.type === ValueType.String && + typeof cell.value === 'string' && + cell.value.substring(0, 11) === '#! END_LOOP' + ); + } + + public apply(scope: Scope): EndLoopCell { + super.apply(scope); + + const target = + scope + .getCurrentTemplateValue() + ?.toString() + .split(' ')[2] || ''; + const __start = scope.vm[target] && scope.vm[target].__start; + const __iterated = scope.vm[target] && scope.vm[target].__iterated; + + scope.unfreezeOutput(); + + scope.vm[target] = Object.freeze({ + ...scope.vm[target], + __end: scope.templateCell, + __insetRows: true, + }); + + if (__start && !__iterated) { + scope.templateCell = __start; + } else { + scope.incrementRow(); + } + + return this; + } +} diff --git a/src/cell/ForEachCell.js b/src/cell/ForEachCell.ts similarity index 68% rename from src/cell/ForEachCell.js rename to src/cell/ForEachCell.ts index 3baf630..846da6f 100644 --- a/src/cell/ForEachCell.js +++ b/src/cell/ForEachCell.ts @@ -1,14 +1,14 @@ -import BaseCell from "./BaseCell"; -import Scope from "../Scope"; -import {ValueType} from "exceljs"; +import { BaseCell } from './BaseCell'; +import { Scope } from '../Scope'; +import { Cell, ValueType } from 'exceljs'; /** - * Pattern: `#! FOR_EACH [TARGET] [FROM]` - * Iterate through `vm[FROM]` and store current item in readonly `vm[TARGET]`. + * Pattern: `#! FOR_EACH [TARGET] [SOURCE]` + * Iterate through `vm[SOURCE]` and store current item in readonly `vm[TARGET]`. * `vm[TARGET]` has additional fields: * - * * `__from` - keeps `FROM` parameter's value - * * `__index` - current 1-based iteration index (`vm[TARGET]` is `vm[FROM][__index-1]`) + * * `__from` - keeps `SOURCE` parameter's value + * * `__index` - current 1-based iteration index (`vm[TARGET]` is `vm[SOURCE][__index-1]`) * * `__start` - template foreach start cell * * `__end` - template loop's end cell, it is undefined before first `END_LOOP` * * `__iterated` - iteration has been finished @@ -16,14 +16,23 @@ import {ValueType} from "exceljs"; * * `__startOutput` - first output cell * * `__endOutput` - last output cell */ -class ForEachCell extends BaseCell { - /** - * @param {Scope} scope - * @returns {ForEachCell} - */ - apply(scope) { - const target = ForEachCell._getTargetParam(scope); - const __from = this._getFromParam(scope); +export class ForEachCell extends BaseCell { + public static match(cell: Cell): boolean { + return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 11) === '#! FOR_EACH'; + } + + protected static getTargetParam(scope: Scope): string { + return scope.getCurrentTemplateValue()?.toString().split(' ')[2] || ''; + } + + protected getSourceParam(scope: Scope): string { + return scope.getCurrentTemplateValue()?.toString().split(' ')[3] || ''; + } + + + public apply(scope: Scope): ForEachCell { + const target = ForEachCell.getTargetParam(scope); + const __from = this.getSourceParam(scope); //todo refactoring const __index = (scope.vm[target] && scope.vm[target].__index || 0) + 1; @@ -56,11 +65,10 @@ class ForEachCell extends BaseCell { __insetRows = false; if (!scope.isFrozen()) { for (let i = __end.r; i > __start.r; i--) { - // noinspection JSCheckFunctionSignatures - todo exceljs signature mismatch scope.output.worksheets[scope.outputCell.ws].spliceRows( //todo refactoring scope.outputCell.r + 1, 0, - scope.template.worksheets[scope.templateCell.ws].getRow(i), + [], ); } } @@ -87,33 +95,4 @@ class ForEachCell extends BaseCell { return this; } - - /** - * @param {Scope} scope - * @returns {string} - * @protected - */ - static _getTargetParam(scope) { - return scope.getCurrentTemplateValue().split(' ')[2]; - } - - /** - * @param {Scope} scope - * @returns {string} - * @protected - */ - _getFromParam(scope) { - return scope.getCurrentTemplateValue().split(' ')[3]; - } - - - /** - * @param {Cell} cell - * @returns {boolean} - */ - static match(cell) { - return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 11) === '#! FOR_EACH'; - } } - -export default ForEachCell \ No newline at end of file diff --git a/src/cell/SumCell.js b/src/cell/SumCell.ts similarity index 53% rename from src/cell/SumCell.js rename to src/cell/SumCell.ts index e158834..80b4d1d 100644 --- a/src/cell/SumCell.js +++ b/src/cell/SumCell.ts @@ -1,16 +1,20 @@ -import BaseCell from "./BaseCell"; -import Scope from "../Scope"; -import {ValueType} from "exceljs"; - -export default class SumCell extends BaseCell { - /** - * @param {Scope} scope - * @returns {SumCell} - */ - apply(scope) { +import { BaseCell } from './BaseCell'; +import { Scope } from '../Scope'; +import { Cell, CellFormulaValue, ValueType } from 'exceljs'; + +export class SumCell extends BaseCell { + public static match(cell: Cell): boolean { + return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 6) === '#! SUM'; + } + + protected static getTargetParam(scope: Scope): string { + return scope.getCurrentTemplateValue()?.toString().split(' ')[2] || ''; + } + + public apply(scope: Scope): SumCell { super.apply(scope); - const target = SumCell._getTargetParam(scope); + const target = SumCell.getTargetParam(scope); const __startOutput = scope.vm[target] && scope.vm[target].__startOutput; const __endOutput = scope.vm[target] && scope.vm[target].__endOutput; @@ -18,28 +22,11 @@ export default class SumCell extends BaseCell { const start = scope.output.worksheets[scope.outputCell.ws].getCell(__startOutput, scope.outputCell.c).address; //todo refactoring const end = scope.output.worksheets[scope.outputCell.ws].getCell(__endOutput, scope.outputCell.c).address; //todo refactoring - scope.setCurrentOutputValue({formula: `sum(${start}:${end})`}); + scope.setCurrentOutputValue({ formula: `sum(${start}:${end})` } as CellFormulaValue); } scope.incrementCol(); return this; } - - /** - * @param {Scope} scope - * @returns {string} - * @protected - */ - static _getTargetParam(scope) { - return scope.getCurrentTemplateValue().split(' ')[2]; - } - - /** - * @param {Cell} cell - * @returns {boolean} - */ - static match(cell) { - return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 6) === '#! SUM'; - } } \ No newline at end of file From 8c8347f299ad0027152115676a8ec58556b5c454 Mon Sep 17 00:00:00 2001 From: Pawel Siemienik Date: Sun, 16 Feb 2020 10:00:42 +0100 Subject: [PATCH 08/10] #2 Ts lint fixation + some refactoring --- package.json | 1 + src/CellTemplateDebugPool.ts | 2 +- src/cell/AverageCell.ts | 22 +++++++++++----------- src/cell/DeleteCell.ts | 4 ++-- src/cell/DumpColsCell.ts | 2 +- src/cell/EndLoopCell.ts | 1 + src/cell/FinishCell.ts | 9 +++------ src/cell/ForEachCell.ts | 13 +++++++------ src/cell/FormulaCell.ts | 32 +++++++++++++------------------- src/cell/HyperlinkCell.ts | 1 - src/cell/SumCell.ts | 5 +++-- src/cell/VariableCell.ts | 1 + src/example.ts | 1 + 13 files changed, 45 insertions(+), 49 deletions(-) diff --git a/package.json b/package.json index 76e9b89..e34fe8f 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "build": "tsc", "format": "prettier --write \"src/**/*.ts\"", "lint": "tslint -p tsconfig.json", + "lint:fix": "tslint -p tsconfig.json --fix", "test": "mocha -r ts-node/register tests/**/*.test.ts", "coverageRaport": "nyc -r lcov -e .ts -x \"*.test.ts\" mocha -r ts-node/register tests/**/*.test.ts && nyc report", "prepublishOnly": "npm test && npm run lint && npm run build", diff --git a/src/CellTemplateDebugPool.ts b/src/CellTemplateDebugPool.ts index 5cee4f6..fc9e3b9 100644 --- a/src/CellTemplateDebugPool.ts +++ b/src/CellTemplateDebugPool.ts @@ -1,7 +1,7 @@ import { CellTemplatePool } from './CellTemplatePool'; import { Cell } from 'exceljs'; import { BaseCell } from './cell/BaseCell'; - +/* tslint:disable:no-console */ export class CellTemplateDebugPool extends CellTemplatePool { /** * do normal match and log in console result. diff --git a/src/cell/AverageCell.ts b/src/cell/AverageCell.ts index 3512512..867858e 100644 --- a/src/cell/AverageCell.ts +++ b/src/cell/AverageCell.ts @@ -1,8 +1,16 @@ import { BaseCell } from './BaseCell'; import { Scope } from '../Scope'; import { Cell, CellFormulaValue, ValueType } from 'exceljs'; - +/* tslint:disable:variable-name */ export class AverageCell extends BaseCell { + + public static match(cell: Cell): boolean { + return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 10) === '#! AVERAGE'; + } + + protected static getTargetParam(scope: Scope): string { + return scope.getCurrentTemplateValue()?.toString().split(' ')[2] || ''; + } public apply(scope: Scope): AverageCell { super.apply(scope); @@ -11,8 +19,8 @@ export class AverageCell extends BaseCell { const __endOutput = scope.vm[target] && scope.vm[target].__endOutput; if (__startOutput && __endOutput) { - const start = scope.output.worksheets[scope.outputCell.ws].getCell(__startOutput, scope.outputCell.c).address; //todo refactoring - const end = scope.output.worksheets[scope.outputCell.ws].getCell(__endOutput, scope.outputCell.c).address; //todo refactoring + const start = scope.output.worksheets[scope.outputCell.ws].getCell(__startOutput, scope.outputCell.c).address; // todo refactoring + const end = scope.output.worksheets[scope.outputCell.ws].getCell(__endOutput, scope.outputCell.c).address; // todo refactoring scope.setCurrentOutputValue({ formula: `average(${start}:${end})` } as CellFormulaValue); } @@ -21,12 +29,4 @@ export class AverageCell extends BaseCell { return this; } - - protected static getTargetParam(scope: Scope): string { - return scope.getCurrentTemplateValue()?.toString().split(' ')[2] || ''; - } - - public static match(cell: Cell): boolean { - return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 10) === '#! AVERAGE'; - } } \ No newline at end of file diff --git a/src/cell/DeleteCell.ts b/src/cell/DeleteCell.ts index cdb228d..963c886 100644 --- a/src/cell/DeleteCell.ts +++ b/src/cell/DeleteCell.ts @@ -10,9 +10,9 @@ export class DeleteCell extends BaseCell { public apply(scope: Scope): DeleteCell { super.apply(scope); - const target = scope.getCurrentTemplateValue()?.toString().split(' ')[2]; //todo make some function for scope.getCurrentTemplateValue()?.toString().split(' ') ; + const target = scope.getCurrentTemplateValue()?.toString().split(' ')[2]; // todo make some function for scope.getCurrentTemplateValue()?.toString().split(' ') ; - if (target == undefined) return this; //it's ok here + if (target === undefined) { return this; } // it's ok here scope.vm[target] = undefined; diff --git a/src/cell/DumpColsCell.ts b/src/cell/DumpColsCell.ts index a1a8167..97f1917 100644 --- a/src/cell/DumpColsCell.ts +++ b/src/cell/DumpColsCell.ts @@ -3,7 +3,7 @@ import { Cell, ValueType } from 'exceljs'; import { Scope } from '../Scope'; export class DumpColsCell extends BaseCell { - static match(cell: Cell): boolean { + public static match(cell: Cell): boolean { return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 12) === '#! DUMP_COLS'; } diff --git a/src/cell/EndLoopCell.ts b/src/cell/EndLoopCell.ts index 0088a68..5efad25 100644 --- a/src/cell/EndLoopCell.ts +++ b/src/cell/EndLoopCell.ts @@ -2,6 +2,7 @@ import { BaseCell } from './BaseCell'; import { Cell, ValueType } from 'exceljs'; import { Scope } from '../Scope'; +/* tslint:disable:variable-name */ export class EndLoopCell extends BaseCell { public static match(cell: Cell): boolean { return ( diff --git a/src/cell/FinishCell.ts b/src/cell/FinishCell.ts index 5422046..9a91d8c 100644 --- a/src/cell/FinishCell.ts +++ b/src/cell/FinishCell.ts @@ -2,6 +2,7 @@ import { BaseCell } from './BaseCell'; import { Cell, ValueType } from 'exceljs'; import { Scope } from '../Scope'; +/* tslint:disable:variable-name */ export class FinishCell extends BaseCell { public static match(cell: Cell): boolean { return ( @@ -18,12 +19,8 @@ export class FinishCell extends BaseCell { * * condition's path follow to undefined * * condition is true * In other way, the same template sheet should render next output sheet - as long as condition is false - * - * @param {Scope} scope - * @returns {boolean} - * @protected */ - private static _getCondition(scope: Scope): boolean { + protected static getCondition(scope: Scope): boolean { const args = scope .getCurrentTemplateValue() @@ -44,7 +41,7 @@ export class FinishCell extends BaseCell { let wst = scope.template.worksheets[scope.templateCell.ws]; - if (FinishCell._getCondition(scope)) { + if (FinishCell.getCondition(scope)) { // todo refactoring scope.iterateWorksheet const wstNext = scope.templateCell.ws + 1; diff --git a/src/cell/ForEachCell.ts b/src/cell/ForEachCell.ts index 846da6f..bb0be56 100644 --- a/src/cell/ForEachCell.ts +++ b/src/cell/ForEachCell.ts @@ -2,6 +2,7 @@ import { BaseCell } from './BaseCell'; import { Scope } from '../Scope'; import { Cell, ValueType } from 'exceljs'; +/* tslint:disable:variable-name */ /** * Pattern: `#! FOR_EACH [TARGET] [SOURCE]` * Iterate through `vm[SOURCE]` and store current item in readonly `vm[TARGET]`. @@ -25,16 +26,12 @@ export class ForEachCell extends BaseCell { return scope.getCurrentTemplateValue()?.toString().split(' ')[2] || ''; } - protected getSourceParam(scope: Scope): string { - return scope.getCurrentTemplateValue()?.toString().split(' ')[3] || ''; - } - public apply(scope: Scope): ForEachCell { const target = ForEachCell.getTargetParam(scope); const __from = this.getSourceParam(scope); - //todo refactoring + // todo refactoring const __index = (scope.vm[target] && scope.vm[target].__index || 0) + 1; if (__index === 1) { super.apply(scope); @@ -65,7 +62,7 @@ export class ForEachCell extends BaseCell { __insetRows = false; if (!scope.isFrozen()) { for (let i = __end.r; i > __start.r; i--) { - scope.output.worksheets[scope.outputCell.ws].spliceRows( //todo refactoring + scope.output.worksheets[scope.outputCell.ws].spliceRows( // todo refactoring scope.outputCell.r + 1, 0, [], @@ -95,4 +92,8 @@ export class ForEachCell extends BaseCell { return this; } + + protected getSourceParam(scope: Scope): string { + return scope.getCurrentTemplateValue()?.toString().split(' ')[3] || ''; + } } diff --git a/src/cell/FormulaCell.ts b/src/cell/FormulaCell.ts index e7026a2..8f3378f 100644 --- a/src/cell/FormulaCell.ts +++ b/src/cell/FormulaCell.ts @@ -1,22 +1,12 @@ -import { BaseCell } from './BaseCell'; -import { Cell, CellFormulaValue, ValueType } from 'exceljs'; -import { Scope } from '../Scope'; +import {BaseCell} from './BaseCell'; +import {Cell, CellFormulaValue, ValueType} from 'exceljs'; +import {Scope} from '../Scope'; export class FormulaCell extends BaseCell { - /** - * @inheritDoc - * @param {Cell} cell - * @returns {boolean} - */ public static match(cell: Cell): boolean { return cell && cell.type === ValueType.Formula; } - /** - * @inheritDoc - * @param {Scope} scope - * @returns {FormulaCell} - */ public apply(scope: Scope): FormulaCell { super.apply(scope); @@ -26,16 +16,20 @@ export class FormulaCell extends BaseCell { const value = scope.getCurrentTemplateValue() as CellFormulaValue; let formula = value.formula; - //todo extract method match addresses - let matches; - let addresses = []; - while (matches = regex.exec(formula)) { + // todo extract method match addresses + const addresses = []; + while (true) { + const matches = regex.exec(formula); + if (matches === null) { + break; + } + addresses.push({index: matches.index, col: matches[1], row: +matches[2], len: matches[0].length}) } addresses.reverse(); - //todo extract method getShiftedFormula - let formulaChars = Array.from(formula); + // todo extract method getShiftedFormula + const formulaChars = Array.from(formula); addresses.forEach(a => formulaChars.splice(a.index, a.len, `${a.col}${a.row + shift}`)); formula = formulaChars.join(''); diff --git a/src/cell/HyperlinkCell.ts b/src/cell/HyperlinkCell.ts index b14d6d2..b9f07bc 100644 --- a/src/cell/HyperlinkCell.ts +++ b/src/cell/HyperlinkCell.ts @@ -23,7 +23,6 @@ export class HyperlinkCell extends BaseCell { const url = HyperlinkCell.getUrlParam(scope).split('.').reduce((p, c) => p[c] || {}, scope.vm); if (typeof url === 'string') { const label = HyperlinkCell.getLabelParam(scope).split('.').reduce((p, c) => p[c] || {}, scope.vm) || url; - console.log(label); scope.setCurrentOutputValue({ text: label, hyperlink: url }); } diff --git a/src/cell/SumCell.ts b/src/cell/SumCell.ts index 80b4d1d..3d93db2 100644 --- a/src/cell/SumCell.ts +++ b/src/cell/SumCell.ts @@ -2,6 +2,7 @@ import { BaseCell } from './BaseCell'; import { Scope } from '../Scope'; import { Cell, CellFormulaValue, ValueType } from 'exceljs'; +/* tslint:disable:variable-name */ export class SumCell extends BaseCell { public static match(cell: Cell): boolean { return cell && cell.type === ValueType.String && typeof cell.value === 'string' && cell.value.substring(0, 6) === '#! SUM'; @@ -19,8 +20,8 @@ export class SumCell extends BaseCell { const __endOutput = scope.vm[target] && scope.vm[target].__endOutput; if (__startOutput && __endOutput) { - const start = scope.output.worksheets[scope.outputCell.ws].getCell(__startOutput, scope.outputCell.c).address; //todo refactoring - const end = scope.output.worksheets[scope.outputCell.ws].getCell(__endOutput, scope.outputCell.c).address; //todo refactoring + const start = scope.output.worksheets[scope.outputCell.ws].getCell(__startOutput, scope.outputCell.c).address; // todo refactoring + const end = scope.output.worksheets[scope.outputCell.ws].getCell(__endOutput, scope.outputCell.c).address; // todo refactoring scope.setCurrentOutputValue({ formula: `sum(${start}:${end})` } as CellFormulaValue); } diff --git a/src/cell/VariableCell.ts b/src/cell/VariableCell.ts index dff3f72..3f4ecef 100644 --- a/src/cell/VariableCell.ts +++ b/src/cell/VariableCell.ts @@ -25,6 +25,7 @@ export class VariableCell extends BaseCell { const value = path.reduce((p, c) => (typeof p === 'object' ? p[c] : p), scope.vm); if (value === undefined) { // todo do it better (use logger or somethink like that) + // tslint:disable-next-line:no-console console.warn( `WARN: ${path} is undefined for output: ${scope.outputCell} when template is:${scope.templateCell}`, ); diff --git a/src/example.ts b/src/example.ts index 48ccadb..64e9431 100644 --- a/src/example.ts +++ b/src/example.ts @@ -3,6 +3,7 @@ import { CellTemplateDebugPool } from './CellTemplateDebugPool'; import { CellTemplatePool } from './CellTemplatePool'; import { Workbook } from 'exceljs'; +// tslint:disable:comment-format //* const debug = true; /*/ From 3f079cc1d122f8c5c1fa6e228a49253d92201789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Siemienik=20Pawe=C5=82?= Date: Thu, 26 Mar 2020 02:25:25 +0100 Subject: [PATCH 09/10] Update nodejs.yml --- .github/workflows/nodejs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 44f7744..b92efa0 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: - node-version: [8.x, 10.x, 12.x] + node-version: [8.x, 10.x, 11.x, 12.x, 13.x] steps: - uses: actions/checkout@v1 From e02fba50230746493a35c52d668b76f7d025087d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Siemienik=20Pawe=C5=82?= Date: Thu, 26 Mar 2020 02:50:05 +0100 Subject: [PATCH 10/10] lock exceljs version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e34fe8f..e8d66c3 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "typescript": "^3.4.4" }, "dependencies": { - "exceljs": "^3.6.1" + "exceljs": "3.8.1" }, "files": [ "lib/**/*"