3.6 KiB
UuidPlugin
Purpose
Generates UUID v4 and URL-safe nano-ID strings inline within templates. Because ID generation depends on crypto.randomUUID or Math.random, the plugin accepts an injectable Rng from @suaveplan/types so tests can produce deterministic output. Each template token renders a freshly generated ID, making the plugin appropriate for generating row identifiers, correlation IDs, or unique slugs during batch template rendering.
Features
{_uuid}— UUID v4 string (xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx).{_uuid:v4}— explicit UUID v4 (same as above).{_nanoid}— 21-character URL-safe nano-ID using the default base-64 alphabet.{_nanoid:10}— nano-ID with custom length.- Injectable
Rngfor fully deterministic output in tests. - Prefers
globalThis.crypto.randomUUID()when available and norngis injected.
Usage: Basic Example
import { TemplateEngine, createUuidPlugin } from "@suaveplan/templates";
const engine = new TemplateEngine().use(createUuidPlugin());
engine.parse("ID: {_uuid}", {});
// → "ID: f47ac10b-58cc-4372-a567-0e02b2c3d479" (random)
engine.parse("Slug: {_nanoid:8}", {});
// → "Slug: V1StGXR8" (random 8-char)
Usage: Advanced Example
import { TemplateEngine, createUuidPlugin } from "@suaveplan/templates";
import type { Rng } from "@suaveplan/types";
// Deterministic RNG for tests
const deterministicRng: Rng = {
nextUint32: () => 0xdeadbeef,
nextFloat: () => 0.42,
};
const engine = new TemplateEngine().use(createUuidPlugin({ rng: deterministicRng }));
const id1 = engine.parse("{_uuid}", {});
const id2 = engine.parse("{_uuid}", {});
// id1 === id2 — same RNG seed produces same output
console.assert(id1 === id2);
// Nano-ID with explicit length
engine.parse("{_nanoid:12}", {});
// → same 12-char string every call with deterministic rng
API Reference
UuidPluginOptions
| Property | Type | Description |
|---|---|---|
rng |
Rng (optional) |
Injectable RNG; if omitted, uses crypto.randomUUID or Math.random |
createUuidPlugin<TContext>(opts?): Plugin<TContext>
Returns a Plugin with:
name: "uuid"priority: PluginPriority.HIGH(80)pattern: /\{_(uuid|nanoid)(?::([^}]+))?\}/g
The pattern captures two groups:
- Type keyword:
uuidornanoid - Optional parameter (
v4for UUID variant, numeric length for nano-ID)
transform(match): Dispatches on the type keyword. For uuid, calls generateUuid(opts.rng). For nanoid, parses the parameter as an integer length (defaults to 21) and calls generateNanoid(length, undefined, opts.rng). Returns the original match text for unrecognised type keywords (defensive — cannot occur given the pattern).
Implementation Notes
generateUuidprefersglobalThis.crypto.randomUUID()when it is available and norngis injected. This avoids manual bit-manipulation and takes advantage of the cryptographically secure native implementation.- When
crypto.randomUUIDis unavailable (older runtimes), the fallback constructs a UUID using the standardxxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxxtemplate with bitwise operations to enforce RFC 4122 version and variant bits. generateNanoiduses modular selection from the alphabet rather than the rejection-sampling algorithm used by thenanoidnpm package. This is sufficient for the lengths and alphabets used in template generation and avoids the complexity of rejection sampling.- Runs at
HIGHpriority so IDs are generated before MEDIUM-priority transforms, allowing{_uuid:upper}style compositions in future plugin extensions.