- Release September 23rd 2020
- Fixes
arrayJoin(\n):convCRLF
. Now it works in carbone v2.x.x like in v1.x.x. - Removes 'zipfile' dev dependency. Tests use unzip from the system instead.
- 8.1.3 mocha upgrade
- Release September 1st, 2020
- Performance: huge gain from x11 to x30 for the compression of reports. Now, some huge reports takes 0.1s to render instead of 4s. It reduces also the blocking of Node's event loop.
- New rendering option
hardRefresh
: The content of the report is refreshed at the end of the Carbone process. For example, it can be used to refresh the table of content or update calculations. The optionconvertTo
has to be defined.
- Release August 10th, 2020
- Fix locales de-ch and pt-br
- Fix direct access in a nested array
{d.array[i].nestedArray[i=0].id}
- Release July 8th, 2020
- Add regression tests
-
Release June 28th, 2020
-
🚀 Accepts dynamic variables in all formatters!
Carbone passes data to formatters if parameters start with a dot
.
and is not surrounded by quotes. Here is an example:Data
{ id : 10, qtyA : 20, subObject : { qtyB : 5, qtyC : 3 }, subArray : [{ id : 1000, qtyE : 3 }] }
Template => Result
do mathematical operations:
{d.subObject.qtyB:add(.qtyC)}
=> 8 (5+3)read parent attributes if you use two dots, grandparents if you use three dots, etc...
{d.subObject.qtyB:add(.qtyC):add(..qtyA)}
=> 28 (5+3+20)read parent objects and their children attributes (no limit in depth)
{d.subArray[i].qtyE:add(..subObject.qtyC)
=> 6 (3+3)It returns an error if the attribute does not exist
{d.subArray[i].qtyE:add(..badAttr)
=> [[C_ERROR]] badAttr not definedYou cannot access arrays
{d.subObject.qtyB:add(..subArray[0].qtyE)}
=> [[C_ERROR]] subArray[0] not defined -
⚡️ New conditional formatters, and a new IF-block system to hide/show a part of the document
ifEQ (value)
: Matches values that are equal to a specified value, it replacesifEqual
ifNE (value)
: Matches all values that are not equal to a specified valueifGT (value)
: Matches values that are greater than a specified value.ifGTE (value)
: Matches values that are greater than or equal to a specified value.ifLT (value)
: Matches values that are less than a specified value.ifLTE (value)
: Matches values that are less than or equal to a specified value.ifIN (value)
: Matches any of the values specified in an array or string, it replacesifContain
ifNIN (value)
: Matches none of the values specified in an array or stringifEM (value)
: Matches empty values, string, arrays or objects, it replacesifEmpty
ifNEM (value)
: Matches not empty values, string, arrays or objectsand (value)
: AND operator between two consecutive conditional formattersor (value)
: (default) OR operator between two consecutive conditional formattershideBegin
andhideEnd
: hide text block between hideBegin and hideEnd if condition is trueshowBegin
andshowEnd
: show a text block between showBegin and showEnd if condition is trueshow (message)
: print a message if condition is trueelseShow (message)
: print a message if condition is falselen()
: returns the length of a string or array.
No formatters can be chained after
hideBegin
,hideEnd
,showBegin
,showEnd
.These new formatters replace the old ones
ifEqual
,ifEmpty
andifContain
. We keep these old formatters for backwards compatibility. You should avoid using them in new templates.Data
{ id : 10, qtyA : 20 }
Template => Result
print simple message according to the result of a condition
{d.id:ifEQ(10):show('hey')}
=> heyprint simple message according to the result of multiple conditions, combining with dynamic variables! 🤩
{d.id:ifEQ(10):and(.qtyA):ifEQ(20):show('hey'):elseShow('hide')}
=> heyhide or show a block of text in the document ⚡️
{d.id:ifEQ(10):showBegin}
block of text{d.id:showEnd}
=> block of text
{d.id:ifEQ(12):showBegin}
block of text{d.id:showEnd}
=>A smart and generic algorithm detects automatically pattern (paragraph, bullet-list, etc) to remove in document even if the conditional block is not placed correctly in XML. For example:
BEGIN<p> blabla END</p>
becomesBEGIN<p> blabla </p>END
. It improves the final result by removing empty spaces in document. -
☀️ Accepts to iterate on attributes of objects as is if it was an array
{ myObject : { paul : '10', jack : '20', bob : '30' } }
In the report:
{d.myObject[i].att} {d.myObject[i].val} {d.myObject[i+1].att} {d.myObject[i+1].val}
- use .att to print the attribute
- use .val to print the value
You can even access nested objects and nested arrays inside
val
:{d.myObject[i].val.myArray[i].id}
-
Fix: avoid crashing when a static image was inserted in a loop in MS Word templates
-
Update totals in ODS and XSLX files
-
formatC
supports many crypto currencies -
Fix: Accepts comma in formatter parameters such as
{d.sentenceExist:ifEqual(1, 'Some sentence, some more sentences.')}
-
Fix: nested array in XML (but not in JSON) was not printed correctly
{d.countries[i].name} {d.movies[i].subObject.name} {d.movies[i+1].subObject.name} {d.countries[i+1].name}
-
Fix: avoid crashing when a sub-object is null or undefined in data
-
Fix: avoid crashing when the parent object of an array is null or undefined in data
-
Eslint code + add eslint tools
-
Fix: accepts dashes characters in JSON data. Before, Carbone crashes when using
{d.my-att-with-dash}
-
Fix: avoid crashing when a XLSX template contains charts
-
Beta: supports dynamic charts rendering in XLSX if these conditions are met:
- first, draw a chart in MS Excel and replace your data with Carbone markers
- datas of the chart should be placed at the top-left corner of the spreadsheet
- all numbers are formatted with formatN() formatter
-
Fix: accepts white-space in array filters with simple quote and double quotes Example:
{d.cars[i, type='Tesla car'].name}
{d.cars[i, type="Tesla car"].name}
-
Fix LibreOffice detection on Windows
-
Remove compatibility with older NodeJS versions (lower than 10.15.0)
-
Upgrade some dependencies (moment, debug, yauzl) and remove useless ones (should)
-
Accepts non-alphanumeric characters in variables names, values, ... For example,
{d.i💎d}
is allowed -
Fix many security issues and reduce memory consumption
-
Fix crash when markers are next to each over
{d.id}{d.other}
in many situations:- with or without conditional blocks
- with or without loops
-
Fix crash when some documents like DOCX contain images in repetition section
-
Accept direct access in arrays such as
{d.myArray[2].val}
instead of{d.myArray[i=2].val}
-
Fix crash when two consecutive arrays, nested in object, were used
-
Remove useless soft-page-break in ODT documents as suggested by the OpenDocument specification
-
LibreOffice 6+ has a memory leak. So Carbone automatically restarts LibreOffice after a certain amount of document conversion. The number of conversions depends on new parameters
factoryMemoryFileSize
andfactoryMemoryThreshold
-
Add conversion timeout parameter
converterFactoryTimeout
(60s by default). It kills LibreOffice if the conversion is too long and returns an error -
Remove deprecated NodeJS "new Buffer"
-
Fix: avoid crashing if a object/array is null or undefined. Print empty text instead.
-
Fix: variables, which begin by the same characters, were not detected correctly since NodeJS 11
- Release June 11, 2019
- Fix
arrayMap()
if used with an array of strings or integer
- Release March 13, 2019
- Add new formatters
convCurr(targetCurrency, sourceCurrency)
to convert from one currency to anotherformatN()
format number according to the locale (lang). Examples:- old
toFixed(2):toFR
can be replaced byformatN(2)
- old
formatC()
format currency according to the locale and the currency- old
toFixed(2)} {t(currency)}
can be replaced byformatC(2)
- old
formatD()
format date according to the locale. Same asconvDate
, but consider parameters are swapped for consistency with formatN. Moreover,patternIn
is ISO8601 by default.convDate()
is deprecatedadd(valueToAdd)
,mul(valueToMultiply)
,sub(valueToSubstract)
,div(value)
: mathematical operationssubstr(start, end)
: slice strings
carbone.set
andcarbone.render
have new optionscurrencySource
: default currency of source data. Ex 'EUR'currencyTarget
: default target currency when the formatterconvCurr
is used without targetcurrencyRates
: rates, based on EUR { EUR : 1, USD : 1.14 }
- Fix memory leaks: one file descriptor remains opened
- Fix crash when template is not correct
- Now
option.lang
must use the i18n format 'fr-fr' instead of just 'fr' - Add fallback to basic sorting when timsort crashes
- Bump debug and moment to fix vulnerabilities
- Remove Support of NodeJS 4
- Release October 11, 2018
- Better Windows support by improving path detection for
soffice
andpython
across all operating platforms. Done by Robert Kawecki (@rkaw92).
- Release February 26, 2018
- Fix: should find markers even if there is a opening bracket
{
before the markers - Fix: accept to nest arrays in XML whereas these arrays are not nested in JSON
- Fix: markers were not parsed if formatters were used directly on
d
orc
like this{d:ifEmpty('yeah')}
... - Fix: keep the first element of the array if the custom iterator is constant
- Fix a lot of strange bugs when using a filter without iterators in arrays (ex.
{d.cities[i=0].temperature}
) - Optimization: gain x10 when sorting 1 Million of rows
- Add formatter
unaccent
to remove accent from string carbone.set
does not overwrite user-defined translations- Accepts iteration on non-XML. Example:
{d[i].brand} , {d[i+1].brand}
- Add new formatters
unaccent()
to remove accent from stringcount()
to print a counter in loops. Usage:{d[i].name:count()}
convCRLF()
to convert text, which contains\r\n
or\n
, into "real" carriage return in odt or docx document
- Formatters which have the property
canInjectXML = true
can inject XML in documents - Return an error in render callback when LibreOffice is not detected
- Get the last object of an array using negative values when filtering with
i
iterator{d.cities[i=-1].temperature}
shows the temperature (if the array is not empty) of the last city{d.cities[i=-2].temperature}
shows the temperature of the city before the last- ...
- Release October 13, 2017
- Automatically remove XML-incompatible control codes (U+0000 to U+0008 and U+000B to U+000C and U+000E to U+001F) before inserting data in templates
- Fix: ifEqual did not work correctly with boolean values
- Release June 7, 2017 - First Public Release, First Public Demo on the Web2day event!
- It loads all lang at startup, and it is able to change the lang at runtime
- Avoid unnecessary synchronous code in
carbone.set
- Improve documentation
- Default template path is working directory by default
- Return the list of supported format when an unknown
options.convertTo
is used - Accept more input type
- Remove deprecated formatters
carbone.set
takes into account changes onfactories
andstartFactory
parameters- Fix: a report without markers, except lang ones, is translated
- Fix: avoid creating LibreOffice zombies when node crashes
- Fix: avoid using LibreOffice if
options.convertTo
equals input file extension - Fix: improve markers detection to avoid removing some XML variable like
{DSDSD-232D}
used in DOCX - Fix: now compatible with node v4.5.0+, v6+, v8+
- Release February 22, 2017
- Access properties of the parent object with two (or more) points
..
and then access children properties as usual:{d.cities[i, temp=20]..country.history.sport.value}
- Do not crash when there is a javascript error during building process
- Improve error outputs: detect when an unknown formatter is used, and propose a correction
- Release February 20, 2017
- Access properties of the parent object with two points
..
or more. Use case: conditional printing of properties using filters in nested arrays:{d.cities[i, temp=20]..countryName}
printsd.countryName
only when the temperature of cities equals 20
- Built-in conditional formatters, which starts by
if
, stop propagation to next formatters if the condition is true - New formatters:
convEnum(d, type)
: convert enums to human readable valuesifEqual(d, value, messageIfTrue, continueOnSuccess)
: show message ifd == value
, and stop propagation to next formatters unlesscontinueOnSuccess
is trueifContain(d, value, messageIfTrue, continueOnSuccess)
: show message ifd contains value
, and stop propagation to next formatters unlesscontinueOnSuccess
is trueprint(d, message)
: print message
- New function
carbone.renderXML(xmlString, data, options, callback)
to render XML directly - Change the lang dynamically in
carbone.render
andcarbone.renderXML
withoptions.lang = 'fr'
. The date formatter is automatically propagated on formatters such asconvDate
- Replace module zipfile by yauzl: faster, lighter, asynchrone
- XLSX templates are accepted (beta)
- Parse embedded XLSX and DOCX documents
- Add a tool to search a text within a marker in all reports
carbone find :formatterName
- Release December 1, 2016
- Bump moment.js to 2.17.0
- Add some powerful and tested formatters:
ifEmpty
,arrayJoin
,arrayMap
,convDate
,lowerCase
,upperCase
,ucFirst
,ucWords
- Fix: in formatters
convert
,format
,addDays
,parse
: if the date is null or undefined these formatters return null or undefined instead of "Invalid Date"
- Fix:
carbone.render
crash ifoptions
containsformatName
withoutformatOptionsRaw
andformatOptions
- Fix: on OSX, the LibreOffice 5.2 path has changed
- Possibility to add the source file extension in
options
when usingconvert(data, convertTo, options, callback)
function. It is mandatory for CSV files otherwise LibreOffice does not understand the file type.
{
fieldSeparator : ',',
textDelimiter : '"',
characterSet : '76',
sourceExtension : '.csv'
}
- Fixed crash when a document cannot be parsed. It returns an error instead of crashing
- Fixed crash when a document cannot be converted (ods -> doc for example). It returns an error instead of crashing
- Update documentation to install LibreOffice 5.1 on Ubuntu Server
- Fix: crashed when using a nested undefined object inside a template
- Upgrade Zipfile, improve some tests for Node.js 4.x compatibility
- Fixed crash when data contains a lot of nested arrays
- Fix a performance issue when a template isn't using iterators at all, this issue caused the array of data to become really big in some cases even though only a small portion of the data was really used
- CarboneJS Server can be used on a remote server. CarboneJS send the document by socket instead of writing a file locally (only when a document conversion occurs)
- CarboneJS Server 0.11 is still compatible with CarboneJS v0.10 clients
- Add two benchmarks tests
- Fix a random failure in a test
-
Allow the comparison operator
!=
in your template:{d.cars[engine.power != 3].name}
-
Add a newline at the end of the lang file
-
Fix: Translation, upper and lower case order does not depend on user's language anymore
-
Do not restart LibreOffice if the document is corrupted (restart it only after 10 consecutive attemps)
-
Return an error when the document cannot be converted
-
Improve stability in general
-
Socket connections have been improved:
- it manages TLS communications
- it increases the delay between two connection attempts exponentially until it reaches a maximum delay of 20sec
-
Fix bugs in tests
-
Compatible with Node v0.12
-
Update zipfile dependency
-
Now, the repetition algorithm can flatten an array of objects!!
- it accepts to increment multiple arrays in the same time
- it repeats automatically all markers that are on the same row of all nested arrays
Example:
Datas:
```
[
{
'site' : {'label':'site_A'},
'cars' : [
{
'name': 'prius',
'spec': {'weight': 1},
'wheels':[
{'brand':'mich'},
{'brand':'cont'}
]
},
{
'name': 'civic',
'spec': {'weight': 2},
'wheels':[
{'brand':'mich'}
]
},
],
},{
'site' : {'label':'site_B'},
'cars' : [{
'name': 'modelS',
'spec': {'weight': 1},
'wheels':[
{'brand':'mich'},
{'brand':'uni' },
{'brand':'cont'}
]
}
],
}
];
```
Template:
site | car name | weight | brand |
---|---|---|---|
{d[i].site.label} | d[i].cars[i].name} | {d[i].cars[i].spec.weight} | {d[i].cars[i].wheels[i].brand} |
{d[i+1].site.label} | d[i+1].cars[i+1].name} | {d[i+1].cars[i+1].spec.weight} | {d[i+1].cars[i+1].wheels[i+1].brand} |
Result:
site | car name | weight | brand |
---|---|---|---|
site_A | prius | 1 | mich |
site_A | prius | 1 | cont |
site_A | civic | 2 | mich |
site_B | modelS | 1 | mich |
site_B | modelS | 1 | uni |
site_B | modelS | 1 | cont |
- Warning: cannot use moxie-zip 0.0.4 because this commit (https://github.com/spocke/moxie-zip/commit/cbc6af14dc2318bbcfcfa82ebaf183c525346ae2) creates wrong *.ods files. The empty directory Bitmap is replaced by a executable file.
- Add new conversion options for CSV export
Now it is possible to pass conversion options to LibreOffice. The attribute convertTo
can be an object instead of a string:
var _options = {
'convertTo' : {
'formatName' : 'csv',
'formatOptions' : {
'fieldSeparator' : '+',
'textDelimiter' : '"',
'characterSet' : '0'
}
}
};
carbone.render(_filePath, data, _options, function(err, result){
...
});
- Add the possibility to pass raw conversion options to LibreOffice. See documentation: https://wiki.openoffice.org/wiki/Documentation/DevGuide/Spreadsheets/Filter_Options
var _options = {
'convertTo' : {
'formatName' : 'csv',
'formatOptionsRaw' : '124,34,0'
}
};
carbone.render(_filePath, data, _options, function(err, result){
...
});
- Improve LibreOffice detection algorithm for Linux. Now, it supports any version of LibreOffice
- BUG fix: When two nested arrays were incremented in the same time
{d.tab[i+1].subtab[i+1]}
, it could generate bad XML in certain cases