Files
skills/docs/foundation/data/templates/src/plugins/transform/RegexPlugin.md
2026-05-29 08:20:56 +01:00

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 using String.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:

  1. Variable path (e.g. phone)
  2. Regex pattern body (e.g. \\D)
  3. Flags string (e.g. g, may be empty)
  4. Operation keyword (replace or a decimal digit string)
  5. 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 RegExp constructor, 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 than RegExp.exec(), which means the g flag causes match() to return all full matches in an array with no group information. Callers wanting capture groups should omit the g flag.
  • The replace operation delegates directly to String.replace(), which respects the g flag: 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 MEDIUM priority so it executes before variable-resolution plugins but after control-flow plugins.