diff --git a/packages/xlsx-renderer/README.md b/packages/xlsx-renderer/README.md
index e53fee1..95058a6 100644
--- a/packages/xlsx-renderer/README.md
+++ b/packages/xlsx-renderer/README.md
@@ -63,19 +63,20 @@ It is possible to use the command line interface [read more about xlsx-renderer-
| - | [BaseCell](./src/cell/BaseCell.ts) | n/o | n/o | All Cell\`s definition classes extend it. | **abstract** |
| Content | [NormalCell](./src/cell/NormalCell.ts) | 1 | not started by `##`, `#!` or `#=` | This one copy all styles, width, properties and value form template. | **default** |
| Content | [VariableCell](./src/cell/VariableCell.ts) | 3 | `## pathToVariable` | Write variable from `ViewModel`.
Paths to object's property or array item are allowed.
When asking about undefined variable it returns empty string. | **Paths examples:**
`simplePath`
`someObject.property`
`array.0.field`
`items.1.path.to.object.prop`|
-| Content | [HyperlinkCell](./src/cell/HyperlinkCell.ts) | 6 | `#! HYPERLINK pathToLabel pathToTarget` | Create a hyperlink. | *Paths resolve exactly same as VariableCell* |
-| Content | [FormulaCell](./src/cell/FormulaCell.ts) | 5 | Cell.type eq. formulae | It handles correctly formulas inside and outside of loops - when rows were shifted compared to the template. | *It is used automatically when formulae from the template being rendered*
[Example](./tests/integration/data/Renderer010-Formula)|
-| Content | [TemplateFormulaCell](./src/cell/TemplateFormulaCell.ts) | 4 | Starts with `#= ` | This one allows you to put a template string into a cell as a formula. To write in a variable use `${pathToVariable}`. | **Example:**
`#= ${summaryFormula}(A2:A${item.__endOutput.r})` gives something like `=MAX(A2:A2910)`
[Example](./tests/integration/data/Renderer017-TemplateFormula)|
+| Content | [TemplateStringCell](./src/cell/TemplateStringCell.ts) | 4 | Starts with #`
| Template string allows you to create advanced text, for example concat two variables or put them into a sentence. To write in a variable use `${pathToVariable}`. | **Example:**
#` Hello ${name}! How are you?
gives for instance `Hello World! How are you?`
[Example](./tests/integration/data/Renderer018-TemplateString)|
+| Content | [HyperlinkCell](./src/cell/HyperlinkCell.ts) | 7 | `#! HYPERLINK pathToLabel pathToTarget` | Create a hyperlink. | *Paths resolve exactly same as VariableCell* |
+| Content | [FormulaCell](./src/cell/FormulaCell.ts) | 6 | Cell.type eq. formulae | It handles correctly formulas inside and outside of loops - when rows were shifted compared to the template. | *It is used automatically when formulae from the template being rendered*
[Example](./tests/integration/data/Renderer010-Formula)|
+| Content | [TemplateFormulaCell](./src/cell/TemplateFormulaCell.ts) | 5 | Starts with `#= ` | This one allows you to put a template string (custom formula) into a cell as a formula. To write in a variable use `${pathToVariable}`. | **Example:**
`#= ${summaryFormula}(A2:A${item.__endOutput.r})` gives something like `=MAX(A2:A2910)`
[Example](./tests/integration/data/Renderer017-TemplateFormula)|
| Navigation | [EndRowCell](./src/cell/EndRowCell.ts) | 2 | `#! END_ROW` | Go to the beginning of next row | |
-| Worksheet
Navigation
Loop | [FinishCell](./src/cell/FinishCell.ts) | 8 | `#! 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) | 14 | `#! 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) | 11 | `#! 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 | [ForEachCell](./src/cell/ForEachCell.ts) | 7 | #! 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) | 10 | `#! 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) | 9 | `#! END_LOOP item` | Mark cell when the loop `item` finished. | |
-| Aggregation| [SumCell](./src/cell/SumCell.ts) | 12 | `#! 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) | 13 | `#! 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) | 15 | `#! DELETE pathToVariable` | Delete variable, useful for nested loops.| [Example](./tests/integration/data/Renderer009-ForEach-Average) |
+| Worksheet
Navigation
Loop | [FinishCell](./src/cell/FinishCell.ts) | 9 | `#! 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) | 15 | `#! 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) | 12 | `#! 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 | [ForEachCell](./src/cell/ForEachCell.ts) | 8 | #! 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) | 11 | `#! 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) | 10 | `#! END_LOOP item` | Mark cell when the loop `item` finished. | |
+| Aggregation| [SumCell](./src/cell/SumCell.ts) | 13 | `#! 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) | 14 | `#! 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) | 16 | `#! DELETE pathToVariable` | Delete variable, useful for nested loops.| [Example](./tests/integration/data/Renderer009-ForEach-Average) |
## Examples
@@ -108,6 +109,8 @@ _These examples might be runned by using the command line tool, [read more](../x
| 15 | [ForEach-merged-two-tables](./tests/integration/data/Renderer015-ForEach-merged-two-tables) | Checks merged cells behaviour |
| 16 | [ForEach-merged-pyramid](./tests/integration/data/Renderer016-ForEach-merged-pyramid) | Checks merged cells behaviour |
| 17 | [TemplateFormulaCell](./tests/integration/data/Renderer017-TemplateFormulaCell) | Dynamic formula creation |
+| 18 | [TemplateStringCell](./tests/integration/data/Renderer018-TemplateStringCell) | Dynamic content creation following by custom template string (`Hello ${name}`). |
+
## Support
@@ -123,9 +126,9 @@ We are ready to provide paid support, in order that please contact me: [hi@siemi
If Node v8 & v9 needed, please contact us [support@siemienik.pl](mailto://support@siemienik.pl).
-## Browser Support
+### ✅ Browser Support
-XLSX Renderer may run on browser side, [read more how to do it](https://github.com/Siemienik/XToolSet/issues/93#issuecomment-732309383).
+XLSX Renderer may run on browser side, [read more how to do it](https://github.com/Siemienik/XToolSet/issues/93).
---
diff --git a/packages/xlsx-renderer/src/CellTemplatePool.ts b/packages/xlsx-renderer/src/CellTemplatePool.ts
index 55beefa..6bd88c4 100644
--- a/packages/xlsx-renderer/src/CellTemplatePool.ts
+++ b/packages/xlsx-renderer/src/CellTemplatePool.ts
@@ -3,6 +3,7 @@ import { Cell } from 'exceljs';
import { BaseCell, CellType } from './cell/BaseCell';
import { NormalCell } from './cell/NormalCell';
import { TemplateFormulaCell } from './cell/TemplateFormulaCell';
+import { TemplateStringCell } from './cell/TemplateStringCell';
import { VariableCell } from './cell/VariableCell';
import { FinishCell } from './cell/FinishCell';
import { ForEachCell } from './cell/ForEachCell';
@@ -22,6 +23,7 @@ export class CellTemplatePool {
NormalCell,
EndRowCell,
VariableCell,
+ TemplateStringCell,
TemplateFormulaCell,
FormulaCell,
HyperlinkCell,
diff --git a/packages/xlsx-renderer/src/cell/NormalCell.ts b/packages/xlsx-renderer/src/cell/NormalCell.ts
index 34f54b3..5ac601d 100644
--- a/packages/xlsx-renderer/src/cell/NormalCell.ts
+++ b/packages/xlsx-renderer/src/cell/NormalCell.ts
@@ -14,7 +14,7 @@ export class NormalCell extends BaseCell {
cell &&
cell.type === ValueType.String &&
typeof cell.value === 'string' &&
- !['##', '#!', "#="].includes(cell.value.substring(0, 2))
+ !['##', '#!', "#=", '#`'].includes(cell.value.substring(0, 2)) // todo documentation: describe prefixes in a documentation
);
}
diff --git a/packages/xlsx-renderer/src/cell/TemplateStringCell.ts b/packages/xlsx-renderer/src/cell/TemplateStringCell.ts
new file mode 100644
index 0000000..41435be
--- /dev/null
+++ b/packages/xlsx-renderer/src/cell/TemplateStringCell.ts
@@ -0,0 +1,56 @@
+import { BaseCell } from './BaseCell';
+import { Cell, ValueType } from 'exceljs';
+import { Scope } from '../Scope';
+
+const variableRegex = /\${[^{]+?}/g;
+
+/**
+ * @description
+ * TemplateStringCellinterpolate string and put it into cell as a string value
+ * * starts width
#`+ */ +export class TemplateStringCell extends BaseCell { + public static match(cell: Cell): boolean { + return ( + cell && + cell.type === ValueType.String && + (cell.isMerged ? cell.master.address === cell.address : true) && + typeof cell.value === 'string' && + cell.value.substring(0, 3) === '#` ' + ); + } + + public apply(scope: Scope): TemplateStringCell { + super.apply(scope); + + const template = scope + .getCurrentTemplateString() + .substring(3); + + const result = template.replace(variableRegex, (match) => { + const path = match.slice(2, -1).split('.'); + + // todo refactoring extract, similar like in VariableCell + const value = path.reduce((p, c) => (typeof p === 'object' ? p[c] : p), scope.vm); + if (value === undefined && !scope.isFrozen()) { + // todo do it better (use logger or something like that) + // tslint:disable-next-line:no-console + console.warn( + `WARN: ${path} is undefined for template string output: ${ + JSON.stringify(scope.outputCell) + } when template is:${ + JSON.stringify(scope.templateCell) + }` + ); + } + + return value; + }); + + // todo refactoring: this is only one line which the logic is different as in TemplateFormulaCell, consider about refactoring + scope.setCurrentOutputValue(result); + scope.incrementCol(); + + return this; + } +} diff --git a/packages/xlsx-renderer/tests/integration/data/Renderer018-TemplateString/expected.xlsx b/packages/xlsx-renderer/tests/integration/data/Renderer018-TemplateString/expected.xlsx new file mode 100644 index 0000000..553e090 Binary files /dev/null and b/packages/xlsx-renderer/tests/integration/data/Renderer018-TemplateString/expected.xlsx differ diff --git a/packages/xlsx-renderer/tests/integration/data/Renderer018-TemplateString/template.xlsx b/packages/xlsx-renderer/tests/integration/data/Renderer018-TemplateString/template.xlsx new file mode 100644 index 0000000..888c071 Binary files /dev/null and b/packages/xlsx-renderer/tests/integration/data/Renderer018-TemplateString/template.xlsx differ diff --git a/packages/xlsx-renderer/tests/integration/data/Renderer018-TemplateString/viewModel.json b/packages/xlsx-renderer/tests/integration/data/Renderer018-TemplateString/viewModel.json new file mode 100644 index 0000000..942d505 --- /dev/null +++ b/packages/xlsx-renderer/tests/integration/data/Renderer018-TemplateString/viewModel.json @@ -0,0 +1,7 @@ +{ + "author": { + "firstName": "Paweł", + "lastName": "Siemienik", + "hobby": "OSS development" + } +}