3.7 KiB
RegexPlugin
Purpose
Applies inline regular-expression operations to resolved context values. The plugin enables match extraction, capture group access, and global search-and-replace — all expressed within the template syntax — so callers can reshape value strings without pre-processing the context object. By centralising regex logic here the main application code stays free of ad-hoc string manipulation.
Features
{path:/pattern/flags}— extract the first match of the regex against the resolved value.{path:/pattern/flags:N}— extract capture group N (0 = full match, 1 = first group, etc.).{path:/pattern/flags:replace:replacement}— replace all occurrences usingString.replace.- Supports all standard regex flags:
g,i,m,s,u,y. - Returns
""for nullish resolved values or when no match is found. - Returns the original match string for invalid regex patterns (safe degradation).
- Skips
_-prefixed paths (reserved for dynamic plugins).
Usage: Basic Example
import { TemplateEngine, createRegexPlugin } from "@suaveplan/templates";
const engine = new TemplateEngine().use(createRegexPlugin());
engine.parse("{phone:/\\D/g:replace:}", { phone: "+1 (555) 867-5309" });
// → "15558675309"
engine.parse("{email:/@.+$/}", { email: "alice@example.com" });
// → "@example.com"
Usage: Advanced Example
import { TemplateEngine, createRegexPlugin } from "@suaveplan/templates";
const engine = new TemplateEngine().use(createRegexPlugin());
// Capture groups: extract year from ISO date
engine.parse(
"Year: {date:/^(\\d{4})-(\\d{2})-(\\d{2})$/:1}",
{ date: "2024-06-15" }
);
// → "Year: 2024"
// Replace non-alphanumeric characters
engine.parse("{code:/[a-z]/gi:replace:X}", { code: "abc123" });
// → "XXX123"
// Out-of-range group returns empty string
engine.parse("{value:/(a)(b)/:9}", { value: "ab" });
// → ""
API Reference
createRegexPlugin<TContext>(): Plugin<TContext>
Returns a Plugin with:
name: "regex"priority: PluginPriority.MEDIUM(50)pattern: /\{([a-zA-Z_$][\w.$]*):\/([^/]+)\/([gimsuy]*)?(?::(\w+)(?::([^}]*))?)?\\}/g
The pattern captures five groups:
- Variable path (e.g.
phone) - Regex pattern body (e.g.
\\D) - Flags string (e.g.
g, may be empty) - Operation keyword (
replaceor a decimal digit string) - Replacement string when operation is
replace
transform(match, context): Resolves the path via getNestedValue, converts the result to a string, then applies the specified operation. Returns SKIP_PLUGIN when path or pattern capture groups are absent. Returns the original match text when the regex constructor throws (malformed pattern). Returns "" for nullish values or when no match exists.
Implementation Notes
- The regex engine used is the native JS
RegExpconstructor, so all platform-supported flags and syntax are available. - When no operation is specified,
String.match()is used and only the zeroth element (the full match) is returned; this is equivalent to requesting group 0 explicitly. - Group extraction uses
String.match()rather thanRegExp.exec(), which means thegflag causesmatch()to return all full matches in an array with no group information. Callers wanting capture groups should omit thegflag. - The
replaceoperation delegates directly toString.replace(), which respects thegflag: without it only the first occurrence is replaced; with it all occurrences are replaced. - Invalid regex patterns are caught silently and the original match text is returned, preventing template rendering from crashing due to user-supplied regex strings.
- Runs at
MEDIUMpriority so it executes before variable-resolution plugins but after control-flow plugins.