From 05a783740357d352812c995877b825a218cf1d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20=40Siemienik?= Date: Sun, 26 Apr 2020 18:36:42 +0200 Subject: [PATCH] #3 #6 iterating thought worksheets, special loop variables, loop twice inserted in ws --- README.md | 25 ++++-------------- tests/integration/Renderer.test.ts | 6 ++--- .../Renderer012-ForEach-special/expected.xlsx | Bin 0 -> 13177 bytes .../Renderer012-ForEach-special/template.xlsx | Bin 0 -> 12417 bytes .../viewModel.json | 9 +++++++ 5 files changed, 16 insertions(+), 24 deletions(-) create mode 100644 tests/integration/data/Renderer012-ForEach-special/expected.xlsx create mode 100644 tests/integration/data/Renderer012-ForEach-special/template.xlsx create mode 100644 tests/integration/data/Renderer012-ForEach-special/viewModel.json diff --git a/README.md b/README.md index 81dd8bc..c7e585e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ # Introduction -This library makes generating xlsx files (Excel) easly. +This library makes generating xlsx files (Excel) easly. It consumes template which is common Excel file, then add yours data (called ViewModel). Blend it and done, as result you'll get pretty Excel. @@ -25,13 +25,13 @@ import Renderer from './xls-renderer/Renderer' const viewModel = new MyAwesomeReportVm(); //or something else (async () => { - const result = await renderer.renderFromFile('./my-awesome-raport-template.xlsx', viewModel); - + const result = await renderer.renderFromFile('./my-awesome-raport-template.xlsx', viewModel); + await result.xlsx.writeFile('./my-awesome-raport.xlsx'); })(); ``` -## More examples: +## More examples: for more example I invite to tests data: [click here and check `Renderer` folders](./tests/integration/data) @@ -50,26 +50,11 @@ for more example I invite to tests data: [click here and check `Renderer` folder | Worksheet
Navigation
Loop | [FinishCell](./src/cell/FinishCell.ts) | 7 | `#! FINISH conditionPath` | Finish rendering for current worksheet and:
1) go to next worksheet if `conditionPath===true`
2) repeat this template worksheet again (`conditionPath === false`) - looping through worksheets
3) finished whole rendering when this worksheet is the last one. | **Examples:**
`#! FINISHED ` or `#! FINISHED itemFromLoop.__iterated` | | Worksheet | [WsNameCell](./src/cell/WsNameCell.ts) | 13 | `#! WS_NAME pathToVariable` | Set worksheet's name. | **Examples:**
`#! WS_NAME worksheetName`
`#! WS_NAME item.title`
`#! WS_NAME translatedNames.0` | | Loop | [DumpColsCell](./src/cell/DumpColsCell.ts) | 10 | `#! DUMP_COLS pathToArray` | Useful for writing through multiple columns. It put each value of array to next column. | [Example](./tests/integration/data/Renderer011-DumpCols/) | -| Loop | **TODO: tests done: simple, stripped; tests todo: nested, with formula, special fields, through worksheets,** [ForEachCell](./src/cell/ForEachCell.ts) | 6 | #! FOR_EACH item items | Begin the loop named `item`, set the first element of `items` into `item` and go to the beginning of next line.| Connected to: `ContinueCell`, `EndLoopCell`, `DeleteCell`, `FinishedCell`, `SumCell`, `AverageCell`. | +| Loop | **TODO: nested loop test, describe special vars** [ForEachCell](./src/cell/ForEachCell.ts) | 6 | #! FOR_EACH item items | Begin the loop named `item`, set the first element of `items` into `item` and go to the beginning of next line.| Connected to: `ContinueCell`, `EndLoopCell`, `DeleteCell`, `FinishedCell`, `SumCell`, `AverageCell`. | | Loop | [ContinueCell](./src/cell/ContinueCell.ts) | 9 | `#! CONTINUE item` | Iterate to next element of loop named `item` (check `ForEachCell` for more information) and navigate to the beginning of new line. | | | Loop | [EndLoopCell](./src/cell/EndLoopCell.ts) | 8 | `#! END_LOOP item` | Mark cell when the loop `item` finished. | | | Aggregation| [SumCell](./src/cell/SumCell.ts) | 11 | `#! SUM item` | Write sum formulae for current column and the `item`'s rows. | [Example](./tests/integration/data/Renderer007-ForEach-Sum/) | | Aggregation | [AverageCell](./src/cell/AverageCell.ts) | 12 | `#! AVERAGE item` | Write average formulae for current column and the `item`'s rows. | [Example](./tests/integration/data/Renderer009-ForEach-Average/) | | View Model | [DeleteCell](./src/cell/DeleteCell.ts) | 14 | `#! DELETE pathToVariable` | Delete variable, useful for nested loops.| [Example](./tests/integration/data/Renderer009-ForEach-Average/) | - -## Commands [PREVIOUS VERSION]: - -1. `#! END_ROW` -4. `#! DELETE varName` -5. `#! HYPERLINK labelVar urlVar` -6. `#! WS_NAME nameVar` set worksheet name -7. `#! FOR_EACH item collection` (to write item property `## item.property`), -8. `#! CONTINUE item` item is set to the next collection item. -9. `#! END_LOOP item` -10. `#! AVERAGE item` write average formula of all items from previous for-each, it has to be placed after the for-each was finished. -11. `#! SUM item` similar to average -12. `#! DUMP_COLS arrayVar` write to next columns all array items (1 item = 1 column) - - [LICENSE](LICENSE) diff --git a/tests/integration/Renderer.test.ts b/tests/integration/Renderer.test.ts index 45ebbd5..5db817c 100644 --- a/tests/integration/Renderer.test.ts +++ b/tests/integration/Renderer.test.ts @@ -79,9 +79,7 @@ describe('INTEGRATION:: Test xlsx renderer ', () => { describe('Load examples, render and compare with expected result', () => { const dataPath = path.normalize(path.join(__dirname, 'data/')); const sets = fs.readdirSync(path.normalize(dataPath), {withFileTypes: true}) - .filter(isDir) - .filter(d => /^Renderer[0-9]*-/.test(d.name)); - + .filter(d => isDir(d) && /^Renderer[0-9]*-/.test(d.name)); const renderer = new Renderer(); sets.forEach(s => { @@ -105,4 +103,4 @@ describe('INTEGRATION:: Test xlsx renderer ', () => { }) }); -}); \ No newline at end of file +}); diff --git a/tests/integration/data/Renderer012-ForEach-special/expected.xlsx b/tests/integration/data/Renderer012-ForEach-special/expected.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e62e6b459840272110b21bec824e842dc61742a0 GIT binary patch literal 13177 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 z zZ~4m8@Mr>z-;%C7E{B5ZWVC?4L`X1z%h9Wo$NyoqSesJ}@vwTM`RQ-MV?^?+#3sgFs5#inu)^O==H zfuQmA((RP$yWL_2K_-^{t!G9iC>RFFe^bAo{o^m=Ux?tp0RDNHe`hBD9N*9D%x9nb zgH8K)rN1+k|B!mVp8qNHgHHQ@Df>?7{W-oXoB3WCeW&;Sq3NHi`%duvIlc?r{1o{2 z1^!O>{X_7XBLA%RSHXc1%cqXhX~ l{P#@yOMHpu&+Y!>{{zTMK>j!nu|Tju%pji+9J=q*{|5pr{0#sA literal 0 HcmV?d00001 diff --git a/tests/integration/data/Renderer012-ForEach-special/template.xlsx b/tests/integration/data/Renderer012-ForEach-special/template.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6bf2313c9df68957b350b868f32cdad42540bdf1 GIT binary patch literal 12417 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 literal 0 HcmV?d00001 diff --git a/tests/integration/data/Renderer012-ForEach-special/viewModel.json b/tests/integration/data/Renderer012-ForEach-special/viewModel.json new file mode 100644 index 0000000..e3ff163 --- /dev/null +++ b/tests/integration/data/Renderer012-ForEach-special/viewModel.json @@ -0,0 +1,9 @@ +{ + "name":"Looping thought ws", + "items":[ + {}, + {}, + {}, + {} + ] +}