From 65c4f959e807d182f16c8dfd2893e094c1cb8692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=40Siemienik=20Pawe=C5=82?= Date: Mon, 20 Nov 2023 23:14:55 +0100 Subject: [PATCH] Using Proxy to prevent against modification the original view model. Fixes https://github.com/Siemienik/XToolset/issues/137 Fixes https://github.com/Siemienik/XToolset/issues/229 --- packages/xlsx-renderer/src/Renderer.ts | 14 +++-------- packages/xlsx-renderer/src/ViewModel.ts | 21 ++++++++++++++++ .../tests/spec/cell-value-type.test.ts | 25 +++++++++++++++++++ 3 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 packages/xlsx-renderer/tests/spec/cell-value-type.test.ts diff --git a/packages/xlsx-renderer/src/Renderer.ts b/packages/xlsx-renderer/src/Renderer.ts index 5fb357c..b4c5a0a 100644 --- a/packages/xlsx-renderer/src/Renderer.ts +++ b/packages/xlsx-renderer/src/Renderer.ts @@ -2,6 +2,7 @@ import { Workbook } from 'exceljs'; import { Scope } from './Scope'; import { CellTemplatePool } from './CellTemplatePool'; +import { createVmProxyHandler } from './ViewModel'; export class Renderer { constructor(private cellTemplatePool: CellTemplatePool = new CellTemplatePool()) {} @@ -10,10 +11,7 @@ export class Renderer { const template = await templateFactory(); const output = await templateFactory(); - // todo Temporary fixation for VM mutating problem, @see https://github.com/Siemienik/XToolset/issues/137 - const vmCopy = JSON.parse(JSON.stringify(vm)); - - const scope = new Scope(template, output, vmCopy); + const scope = new Scope(template, output, new Proxy(vm, createVmProxyHandler())); while (!scope.isFinished()) { this.cellTemplatePool.match(scope.getCurrentTemplateCell()).apply(scope); @@ -23,20 +21,16 @@ export class Renderer { } public async renderFromFile(templatePath: string, viewModel: unknown): Promise { - const result = await this.render(async () => { + return this.render(async () => { const template = new Workbook(); return await template.xlsx.readFile(templatePath); }, viewModel); - - return await result; } public async renderFromArrayBuffer(templateArrayBuffer: ArrayBuffer, viewModel: unknown): Promise { - const result = await this.render(async () => { + return this.render(async () => { const template = new Workbook(); return await template.xlsx.load(templateArrayBuffer); }, viewModel); - - return await result; } } diff --git a/packages/xlsx-renderer/src/ViewModel.ts b/packages/xlsx-renderer/src/ViewModel.ts index e5671f0..09481fd 100644 --- a/packages/xlsx-renderer/src/ViewModel.ts +++ b/packages/xlsx-renderer/src/ViewModel.ts @@ -1 +1,22 @@ export type ViewModel = any; + +export const createVmProxyHandler = ()=> { + const data: Record = {}; + + return { + get(target: any, p: PropertyKey): any { + if (typeof p !== 'string' && typeof p !== 'number') { + return; + } + return p in data ? data[p] : target[p] + }, + set(target: unknown, p: PropertyKey, value: unknown): boolean { + if (typeof p !== 'string' && typeof p !== 'number') { + return false; + } + data[p] = value + + return true + }, + } +} diff --git a/packages/xlsx-renderer/tests/spec/cell-value-type.test.ts b/packages/xlsx-renderer/tests/spec/cell-value-type.test.ts new file mode 100644 index 0000000..e8a956d --- /dev/null +++ b/packages/xlsx-renderer/tests/spec/cell-value-type.test.ts @@ -0,0 +1,25 @@ +import * as chai from 'chai'; +import { CellValue, Workbook } from 'exceljs'; +import { ValueType } from 'exceljs'; +import { Renderer } from '../../src/Renderer'; + +const WS_NAME = 'test ws'; + +describe('BaseCell unit tests', () => { + const factory = async ():Promise =>{ + const template = new Workbook(); + template.addWorksheet(WS_NAME).addRow(['## testVar', "#! FINISH"]); + + return template; + } + + it('DateTime', async () => { + const viewModel = { + testVar: new Date(2023, 11, 17, 21, 37) + } + const renderer = new Renderer(); + const output = await renderer.render(factory, viewModel) + + chai.expect(output.getWorksheet(WS_NAME)?.getCell('A1').type).equals(ValueType.Date); + }); +});