String Manipulation

Content Type: Module
Categories: Utility

Overview

Utilized for modifying, parsing, or examining strings (sequences of characters) in processes like data cleaning, text processing, and producing formatted output.

Documentation

Typical usage scenario


Mendix gives you a small set of string functions in expressions — toUpperCase, substring, trim, find, replaceAll — and once you need anything beyond that you end up writing the same throwaway JavaScript action for the third time in the third app. String Manipulation packages 35 client-side JavaScript actions that cover the awkward cases: case conversion into every convention a downstream system might expect, padding, trimming by count rather than by whitespace, substring extraction anchored on the last occurrence of a delimiter, and a set of Unicode-aware operations that treat emoji and combining characters as single visual characters rather than as UTF-16 code units. Every action is a nanoflow activity, so it runs in the browser or in the native client with no round trip to the runtime.


• Normalising identifiers for an integration. A REST or

Kafka partner expects snake_case keys, an OData feed expects PascalCase, an

HTTP header wants Header-Case. Convert in a nanoflow before you build the

request body instead of hand-rolling regular expressions in a microflow.

• Formatting reference codes and fixed-width output.

Left-pad an order number to ten characters with zeros, right-pad a description

to a fixed column width for a legacy flat-file export, or pad a value to an

exact width.

• Cleaning user or imported text. Strip a UTF-8 byte order

mark left behind by an Excel export, remove punctuation before fuzzy matching,

or remove a configured list of stop words from a free-text field before storing

it.

• Splitting paths, URLs and delimited values. Take

everything after the last / to get a filename, or everything before the last .

to drop an extension, without writing an index-arithmetic expression that

breaks on edge cases.

• Displaying long values without breaking a layout. Truncate

in the middle with a replacement sequence so both ends of a long file path or

account reference stay readable in a data grid cell.

• Working correctly with emoji and accented text. Reverse a

string by grapheme cluster rather than by code unit, find grapheme cluster and

code point boundaries, percent-encode a value for a URL to RFC 3986, or convert

a UTF-16 string to its UTF-8 byte sequence.

• Turning numbers into words. Render an amount as English

words for a cheque, an invoice total in words, or an accessibility label.


The underlying problem this solves is that the Mendix

expression language has no string library worth the name, and the alternative —

a bespoke JavaScript action per app, per developer, per project — produces code

that is untested, undocumented and duplicated across your portfolio. This

module replaces that with one import and a documented set of actions backed by

stdlib, an established, Apache-2.0 licensed string and numerical library.


Features and limitations


All 35 actions are nanoflow JavaScript actions (platform:

All — web and native), grouped into folders in the App Explorer.


Case conversion — pascalCase, snakeCase (Foo Bar → foo_bar),

kebabCase (foo-bar), dotCase (foo.bar), constantCase (FOO_BAR), headerCase

(Foo-Bar), startCase, uncapitalize


Padding — lpad and rpad (Input, length, pad — pads to a

length of at least length; leave pad empty for a space), pad (Input, length —

right-pads with spaces to exactly length)


Trimming — ltrim, rtrim (whitespace), ltrimN (removes n

characters from the beginning), rtrimN (from the end)


Removing characters — removeFirst, removeLast,

removePunctuation, removeUTF8BOM, removeWords (words is a comma-separated list,

plus an ignoreCase Boolean)


Splitting and substrings — substringBeforeLast,

substringAfterLast (fromIndex is mandatory — see Known bugs), truncateMiddle

(length is the total output length including the replacement sequence),

splitGraphemeClusters (returns clusters joined by commas, not a list)


Unicode, code points and grapheme clusters — codePointAt

(Input, Position → Integer), fromCodePoint (comma-separated code points, 97,

98, 99 → abc), nextCodePointIndex, nextGraphemeClusterBreak,

prevGraphemeClusterBreak (see Known bugs)


Encoding — percentEncode (RFC 3986), utf16ToUTF8 (UTF-8 byte

values joined by commas)


Other — acronym (the quick brown fox → QBF, common English

stop words skipped), num2words (87 → eighty-seven, English only), repeat,

reverseString (reverses by grapheme cluster, so emoji and accents survive)


Also included — a module role StringManipulation.User, and

an _Example folder with one nanoflow calling every action in sequence against

sample values. Use it as a smoke test and as a reference for parameter shapes.


Limitations


• Client-side only. These are JavaScript actions, usable

from nanoflows only. You cannot call them from a microflow, a scheduled event,

an after-startup flow, or a published service implemented in a microflow.

• The package is roughly 43 MB. It bundles the full @stdlib

dependency tree — 43 npm packages, about 30,400 files, around 130 MB once

unpacked. This is how the module has always been built; it is not an artefact

of the 10.x conversion. Expect a larger repository, slower Git operations,

slower first deployments and longer client bundle builds. The webpack build

only includes what the actions actually reach, so the runtime client payload is

far smaller than the package — but the source footprint in your app directory

is not.

• No domain model. No entities, no attributes, no pages. It

is a pure function library.

• Only a subset of stdlib is exposed. The bundled

@stdlib/string 0.2.1 also offers camelcase, capitalize, lowercase, uppercase,

trim, truncate, startsWith, endsWith, first, replace, replaceBefore,

substringBefore, substringAfter and numGraphemeClusters, none of which have an

action. Several are already covered by Mendix expressions.

• Library options are not exposed. acronym cannot take a

custom stop-word list; num2words is fixed to English and to Integer input, so

the library's decimal support and its lang option are unreachable;

reverseString cannot be switched from grapheme mode; pad cannot use the

lpad/rpad/centerRight options; codePointAt does not expose the backward flag;

ltrimN and rtrimN cannot take a custom character set.

• List-shaped values are handled as comma-joined strings.

splitGraphemeClusters and utf16ToUTF8 join results with commas; fromCodePoint

and removeWords take comma-separated input. If your data contains commas you

will need a different delimiter strategy.

• No locale or collation awareness. Case conversion follows

the library's ASCII-oriented word-splitting rules, not CLDR locale rules. No

Turkish dotless-i handling, no locale-sensitive comparison or sorting.

• No regular expression, formatting or templating actions.


Dependencies


• Mendix Studio Pro 10.24.17 or above — built and tested on

10.24.17, converted from 9.24.12.

• Nanoflow Commons — only for the _Example nanoflow, which calls ShowProgress and HideProgress. None of the 35 actions reference it.

• npm packages are bundled — @stdlib/string 0.2.1 and its transitive tree ship inside the package, with package.json and package-lock.json. No network access is needed at import or build time, and no

npm install step. Versions are pinned to the lock file; you upgrade by replacing the folder yourself.

• The bundled library is Apache-2.0 (stdlib), with permissive licences on the eleven transitive packages.

• No Java dependencies, no JAR files, no custom runtime settings, no constants.


Installation


1. Open your app in Studio Pro 10.24.17 or above.

2. If you want the _Example nanoflow error-free, install

Nanoflow Commons from the Marketplace first. Otherwise plan to delete the

_Example folder after import.

3. In Studio Pro choose App Explorer > right-click the

app node > Import module package, select StringManipulation.mpk and import

it as a new module.

4. Expect the import to take a while. About 43 MB

compressed, expanding to roughly 130 MB across some 30,400 files. If it looks

like it has hung, antivirus real-time scanning is the usual cause.

5. Press F4 and confirm the module is clean. The only errors

you should see are the two Nanoflow Commons references, if you skipped

step 2.

6. If you do not want the example, delete the _Example

folder. Nothing else depends on it.

7. Deploy locally once (F5). The first build is slower than

usual; later builds are cached.

8. Commit

javascriptsource/stringmanipulation/actions/node_modules along with the rest —

it is part of the module and is needed for teammates and for the cloud build,

so your repository will grow by roughly 130 MB.


Configuration


Nothing to configure at module level — no constants, no

scheduled events, no entity access. Configuration happens per action, at the

call site.


General pattern. Every action takes its subject as the first

parameter, named Input, and returns a value. Leave Use return value enabled and

give the output variable a meaningful name.


Empty input. Every action guards and throws when Input is

empty. A required parameter still accepts an expression that evaluates to

empty, so the guard is reachable. Either test for empty before the call or set

the activity's error handling to Custom with rollback. Do not rely on empty in,

empty out — it does not happen.


Case conversion. These convert words, not identifiers: pass

human-readable text ('my order number') rather than already-mangled input, and

check the output against your target system's exact convention.


Padding. lpad / rpad: length is a minimum, not an exact

width — if the pad string does not divide evenly the result can be longer. Use

a single-character pad ('0', ' ') when you need exact width. pad takes Input

and length only, right-padding with spaces. Leave the pad parameter empty to

fall back to a space.


Trimming. ltrimN trims from the beginning and rtrimN from

the end, regardless of what the tooltip says (see Known bugs).


Comma-separated parameters. removeWords takes words as

'boop,foo'; fromCodePoint takes Input as '97, 98, 99'. Whitespace after a comma

is tolerated by fromCodePoint; non-numeric entries are not, so validate first.

removeWords also takes a required ignoreCase Boolean — pass false for exact

matching.


Substrings. substringBeforeLast returns an empty string when

search is not found. For substringAfterLast, pass length($Input) as fromIndex

to get ordinary "after the last occurrence" behaviour — passing 0

restricts the search to a match starting at index 0 and will usually return

empty. For truncateMiddle, length is the total output length including seq.


Unicode. The length parameter on nextCodePointIndex and

nextGraphemeClusterBreak is a starting position in UTF-16 code units, not a

length — it maps to the library's fromIndex. Positions refer to code units, not

visible characters, so on emoji or combining-character text an index and a

visual character position are not the same thing.


Recommended pattern. Wrap the actions you actually use in

thin nanoflows inside your own module — SUB_FormatOrderReference calling lpad,

or SUB_ToSnakeCase calling snakeCase behind an empty-input guard. One place for

the empty check, one place for error handling, one place to change if you swap

the implementation.


Known bugs

None


Frequently Asked Questions


Why is the package 43 MB?

It ships the entire @stdlib dependency tree — 43 npm packages, about 30,400 files, roughly 130 MB unpacked — so that no npm install is needed at import or build time. The size is inherited from how the module has always been packaged and is not a side effect of the Studio Pro 10 conversion.


Does that 43 MB end up in my end users' browsers?

No. The webpack build only includes the code the actions actually reach. What grows permanently is your app directory, your Git repository and your first-build time — not the runtime download.


Can I delete the parts of node_modules I do not use?

Not safely. The @stdlib/string namespace index requires every sub-package, so a partial tree breaks the require('@stdlib/string') call that every action makes. If you only need a handful of actions, delete the actions you do not want and leave node_modules intact.


Can I call these from a microflow?

No. They run only in nanoflows, on the client. There is no server-side equivalent in this module.


Do the actions work in a native mobile app?

All 35 are set to platform "All", so Studio Pro allows them in native nanoflows. The library is plain JavaScript with no DOM or Node dependency, so behaviour should be identical, though native has had less testing than web.


Which Studio Pro versions are supported?

10.24.17 and above. Converted from 9.24.12; if you are still on Mendix 9, use the previous release.


Do I need Nanoflow Commons?

Only for the _Example nanoflow. Delete that folder after import and the module has no Marketplace dependencies at all.


Are there entities I need to grant access to?

No. The module has no domain model. It ships a single module role, StringManipulation.User, which you can assign if you want the example nanoflow to be callable.


What happens if I pass an empty string?

Every action throws an error rather than returning empty. Guard for empty before the call, or set the activity's error handling to Custom with rollback. The codePointAt guard was corrected in 2.1.


Why do some actions use comma-separated strings instead of lists?

Nanoflow JavaScript actions cannot take a list of primitives as a parameter, so removeWords and fromCodePoint accept a comma-separated string, and splitGraphemeClusters and utf16ToUTF8 return one. If your data contains commas you will need to pre-process it.


Does reverseString handle emoji correctly?

Yes. It reverses by extended grapheme cluster by default, so emoji, flags and combining accents stay intact. The library's code point and code unit modes are not exposed.


Is the module safe to use with untrusted input?

The actions are pure string transformations with no eval, no network calls and no DOM access. They do not escape for HTML — percentEncode is for URLs, not markup — so continue to rely on Mendix's own output escaping.


Issues, suggestions and feature requests:

https://github.com/bharathidas/String-Manipulation/issues

Releases

Version: 2.1.1
Framework Version: 10.24.17
Release Notes:

**String Manipulation** — Studio Pro **10.24.17**


### Fixed — Marketplace security scan failure (CWE-494)


The Marketplace scan failed this module with a **CRITICAL** finding:


> `javascriptsource/stringmanipulation/actions/package-lock.json` — The package-lock.json file contains at least 1 library whose integrity is not checked. ([CWE-494](https://cwe.mitre.org/data/definitions/494.html))


**Cause.** Of the 43 entries in the lock file, only the direct dependency `@stdlib/string` carried `resolved` and `integrity`. All **42 transitive `@stdlib` packages had neither** — just a version number. Without an integrity hash, npm cannot verify what it downloads, which is the supply-chain risk the scan is designed to catch.


**Fix.** The lock file has been regenerated against the npm registry so that every entry carries both `resolved` and `integrity`, in the modern `packages` block and the legacy `dependencies` block alike.


| | Before | After |

|---|---|---|

| Entries | 43 | 43 |

| Missing `integrity` | **42** | **0** |

| Missing `resolved` | 42 | 0 |


**The shipped code is unchanged.** Every one of the 43 pinned versions in the regenerated lock was compared against the `node_modules` tree that ships in this package — 43 identical, 0 mismatches, nothing added, nothing removed. The lock now describes exactly the tree it always described; it simply records the hashes as well. Integrity hashes were spot-checked against the registry for `@stdlib/array@0.2.1`, `@stdlib/utils@0.2.1`, `@stdlib/types@0.3.2` and `debug@2.6.9`.


The `codePointAt` fix from 2.1 is retained.


### Notes

Studio Pro 10.24.17, imports with 0 errors. 35 actions over the bundled `@stdlib/string` 0.2.1. Import `StringManipulation.mpk` via *App Explorer > Import module package*.

Version: 1.0.0
Framework Version: 9.12.4
Release Notes: Utilized for modifying, parsing, or examining strings (sequences of characters) in processes like data cleaning, text processing, and producing formatted output. **Features** **Padding** • **lpad** - left pad a string • **rpad** - right pad a string • **pad** - pad a string **Trimming** • **ltrim** - trim whitespace characters from the beginning of a string • **rtrim** - trim whitespace characters from the end of a string • **ltrimN** - trim n characters from the end of a string • **rtrimN** - trim n characters from the end of a string **Case Conversion** • **constantCase** - convert a string to constant case • **dotCase** - convert a string to dot case • **headerCase** - convert a string to HTTP header case • **kebabCase** - convert a string to kebab case • **pascalCase** - convert a string to Pascal case • **snakeCase** - convert a string to snake case • **startCase** - capitalize the first letter of each word in a string **Removing Characters** • **removeFirst** - remove the first character(s) of a string • **removeLast** - remove the last character(s) of a string • **removePunctuation** - remove punctuation characters from a string • **removeUTF8BOM** - remove a UTF-8 byte order mark (BOM) from the beginning of a string • **removeWords** - remove a list of words from a string **Splitting and Substrings** • **splitGraphemeClusters** - split a string by its grapheme cluster breaks • **substringAfterLast** - return the part of a string after the last occurrence of a specified substring • **substringBeforeLast** - return the part of a string before the last occurrence of a specified substring • **truncateMiddle** - truncate a string in the middle to a specified length **Repeating and Reversing** • **repeat** - repeat a string a specified number of times and return the concatenated result • **reverseString** - reverse a string **Encoding** • **percentEncode** - percent-encode a UTF-16 encoded string according to RFC 3986 • **utf16ToUTF8** - convert a UTF-16 encoded string to an array of integers using UTF-8 encoding **Unicode and Grapheme Clusters** • **codePointAt** - return a Unicode code point from a string at a specified position • **fromCodePoint** - create a string from a sequence of Unicode code points • **nextCodePointIndex** - return the position of the next Unicode code point in a string after a specified position • **nextGraphemeClusterBreak** - return the next extended grapheme cluster break in a string after a specified position • **prevGraphemeClusterBreak** - return the previous extended grapheme cluster break in a string before a specified position **Number Conversion** • **num2words** - convert a number to a word representation **Misc** • **Acronym** - generate an acronym for a given string • **uncapitalize** - uncapitalize the first character of a string **Dependencies**: • Mendix modeler 9.12.4. **Issues, suggestions and feature requests** [https://github.com/bharathidas/String-Manipulation/issues](https://github.com/bharathidas/String-Manipulation/issues)