Release r202623
What's new
This release contains the following new feature:
Replacing matches with a function
replace and replaceAll previously accepted only a string as the replacement. They now also accept a function, the
same way they do in JavaScript. The function is called for every match and returns the text to replace the match with,
which makes it possible to compute a replacement from the text that was matched:
const name = "ellen brown";
const capitalized = name.replace(/\b\w/g, (letter) => letter.toUpperCase());
log(capitalized);
// => Ellen Brown
For those of us whose regular expressions have gone a little rusty, the /\b\w/g pattern is built from three
parts:
\b: a word boundary, the position between a non-word character and a word character.\w: a single word character, so together with\bit matches the first letter of a word.g: the global flag, which applies the replacement to every word instead of only the first one.
Continuing on that example, the replace function also receives the offset of the match, the position in the text where the match starts. With it, we can change the function to only capitalize the first word of the given text:
const text = "printer is offline";
const capitalizedFirst = text.replace(/\b\w/g, (letter, offset) => {
return offset === 0 ? letter.toUpperCase() : letter;
});
log(capitalizedFirst);
// => Printer is offline
The replace function also receives the capture groups of the pattern, and the subject string as its last argument. That makes more advanced use cases possible, for example templating:
const values = [
{ name: "Ellen", id: 705736 },
{ name: "Howard", id: 705741 },
];
const template = "Hello {name}, your request {id} has been closed.";
values.forEach((value) => {
log(template.replace(/{(\w+)}/g, (match, field) => value[field] ?? match));
});
// => Hello Ellen, your request 705736 has been closed.
// => Hello Howard, your request 705741 has been closed.
The /{(\w+)}/g pattern is built from three parts:
{and}: the literal braces that surround a placeholder.(\w+): one or more word characters. The parentheses make it a capture group, which means the text it matches is passed to the function as a separate argument, in this casefield.g: the global flag again, so every placeholder is replaced instead of only the first one.
See replace and replaceAll in the built-in objects reference.
Other changes
This release contains the following smaller changes:
- Template names: two rules have changed.
- The name no longer has to consist of letters, numbers, underscores and hyphens, so a name such as
Order confirmation (NL)is now accepted. - The name has to be unique within the environment.
- The name no longer has to consist of letters, numbers, underscores and hyphens, so a name such as
- Package scripts will now consistently use LF line endings. Previously, some scripts used CRLF line endings or mixed both types. All existing packages will be converted to LF. This does not affect functionality and will not show up in the change history.
- Fix: in our Xurrent REST API model, the
shop_articleproperty of a shop order line was treated as a reference to a shop article, so reading it triggered an auto-fetch (that failed), while the property holds a plain string. Useshop_article_idto set the shop article of a line. See Shop order lines. - Fix: in some cases, a package execution could reuse an OAuth token that was 1 or 2 seconds after the token expiry time. This has been fixed by adding a 1 minute safety margin.
Timeline
The expected deployment dates for this release are:
| Environment | Date |
|---|---|
| Demo | Friday, September 11 |
| Production | Tuesday, September 15 |
The deployment to the Production environment will be conducted outside of office hours (Central European Time Zone), usually between 8 and 10pm.