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

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 Rng for fully deterministic output in tests.
  • Prefers globalThis.crypto.randomUUID() when available and no rng is 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:

  1. Type keyword: uuid or nanoid
  2. Optional parameter (v4 for 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

  • generateUuid prefers globalThis.crypto.randomUUID() when it is available and no rng is injected. This avoids manual bit-manipulation and takes advantage of the cryptographically secure native implementation.
  • When crypto.randomUUID is unavailable (older runtimes), the fallback constructs a UUID using the standard xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx template with bitwise operations to enforce RFC 4122 version and variant bits.
  • generateNanoid uses modular selection from the alphabet rather than the rejection-sampling algorithm used by the nanoid npm package. This is sufficient for the lengths and alphabets used in template generation and avoids the complexity of rejection sampling.
  • Runs at HIGH priority so IDs are generated before MEDIUM-priority transforms, allowing {_uuid:upper} style compositions in future plugin extensions.