Skip to main content

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 \b it 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 case field.
  • 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.
  • 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_article property 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. Use shop_article_id to 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:

EnvironmentDate
DemoFriday, September 11
ProductionTuesday, September 15

The deployment to the Production environment will be conducted outside of office hours (Central European Time Zone), usually between 8 and 10pm.